@@ -159,7 +159,7 @@ declaratively map exception fields to a `Problem`.
159159To extract values from target exception, it's possible to use placeholders for interpolation.
160160
161161- ` {message} ` - the exact ` getMessage() ` result from your exception,
162- - ` {traceId} ` - the ` context.getTraceId() ` result for tracking error response with the actual request. The ` context ` is
162+ - ` {context. traceId} ` - the ` context.getTraceId() ` result for tracking error response with the actual request. The ` context ` is
163163 something that is build in ` @RestControllerAdvice ` s and it contains processing metadata. Currently only ` traceId ` is
164164 supported,
165165- ` {fieldName} ` - any field name declared in exceptions and its superclasses (scanned from current class to its most
@@ -184,7 +184,7 @@ To extract values from target exception, it's possible to use placeholders for i
184184 title = " Invalid Request" ,
185185 status = 400 ,
186186 detail = " {message}: {fieldName}" ,
187- instance = " https://example.org/instances/{traceId}" ,
187+ instance = " https://example.org/instances/{context. traceId}" ,
188188 extensions = {" userId" , " fieldName" })
189189public class ExampleException extends RuntimeException {
190190
@@ -237,7 +237,7 @@ public class MaxUploadSizeExceededResolver implements ProblemResolver {
237237```
238238
239239` ProblemResolver ` implementations return a ` ProblemBuilder ` for flexibility in constructing the final ` Problem ` object.
240- It's a convenience for additional ` Problem ` processing (such as ` instance-override ` feature) .
240+ It's a convenience method for further extending ` Problem ` object by processing downstream .
241241
242242#### Custom ` @RestControllerAdvice `
243243
@@ -257,36 +257,40 @@ If you want your advice to override the ones provided by this library, use a sma
257257| ` ProblemException ` | ` Ordered.LOWEST_PRECEDENCE - 10 ` |
258258| ` Exception ` | ` Ordered.LOWEST_PRECEDENCE ` |
259259
260- While implementing custom ` @ControllerAdvice ` , enforcing ` instance-override ` feature must be performed manually. Value
261- of ` "instance" ` field will come from request attributes and must be overwritten if not ` null ` .
260+ While implementing custom ` @ControllerAdvice ` , don't forget of calling ` ProblemPostProcessor ` manually, before returning
261+ ` Problem ` object.
262262
263263``` java
264264@Order (Ordered . LOWEST_PRECEDENCE - 20 )
265265@Component
266266@RestControllerAdvice
267267public class ExampleExceptionAdvice {
268268
269+ private final ProblemPostProcessor problemPostProcessor;
270+
271+ // constructor
272+
269273 @ExceptionHandler (ExampleException . class)
270274 public ResponseEntity<Problem > handleExampleException (ExampleException ex , WebRequest request ) {
271- ProblemBuilder =
275+ ProblemContext context = (ProblemContext ) request. getAttribute(PROBLEM_CONTEXT , SCOPE_REQUEST );
276+ if (context == null ) {
277+ context = ProblemContext . empty();
278+ }
279+
280+ HttpHeaders headers = new HttpHeaders ();
281+ headers. setContentType(MediaType . APPLICATION_PROBLEM_JSON );
282+
283+ Problem problem =
272284 Problem . builder()
273285 .type(" https://example.org/errors/invalid-request" )
274286 .title(" Invalid Request" )
275287 .status(400 )
276288 .detail(ex. getMessage())
277289 .instance(" https://example.org/instances/" + context. getTraceId())
278290 .extension(" userId" , e. getUserId())
279- .extension(" fieldName" , e. getFieldName());
280-
281- Object instanceOverride = request. getAttribute(TracingSupport . INSTANCE_OVERRIDE , SCOPE_REQUEST );
282- if (instanceOverride != null ) {
283- builder = builder. instance(instanceOverride. toString());
284- }
285-
286- Problem problem = builder. build();
287-
288- HttpHeaders headers = new HttpHeaders ();
289- headers. setContentType(MediaType . APPLICATION_PROBLEM_JSON );
291+ .extension(" fieldName" , e. getFieldName())
292+ .build();
293+ problem = problemPostProcessor. process(context, problem);
290294
291295 HttpStatus status = ProblemSupport . resolveStatus(problem. getStatus());
292296
@@ -538,24 +542,62 @@ Library can be configured with following properties.
538542
539543### ` problem4j.detail-format `
540544
541- Property that specifies how exception handling imported with this module should print ` "detail" ` field of ` Problem `
542- model (` lowercase ` , ** ` capitalized ` - default** , ` uppercase ` ). Useful for keeping the same style of errors coming from
543- library and your application.
545+ Property that specifies how exception handling imported with this module should print the ` "detail" ` field of the
546+ ` Problem ` model (` lowercase ` , ** ` capitalized ` - default** , ` uppercase ` ). Useful for keeping a consistent style between
547+ errors generated by the library and those from your application.
544548
545549### ` problem4j.tracing-header-name `
546550
547551Property that specifies the name of the HTTP header used for tracing requests. If set, the trace identifier from this
548- header can be injected into the ` Problem ` response, for example into the` "instance" ` field when combined with
549- [ ` problem4j.instance-override ` ] ( #problem4jinstance-override ) . Defaults to ` null ` (disabled).
552+ header is extracted and made available within the request context (` ProblemContext ` ). This value can be referenced in
553+ other configuration properties using the ` {context.traceId} ` placeholder. Defaults to ` null ` (disabled).
554+
555+ ### ` problem4j.type-override `
556+
557+ This property allow overriding the ` "type" ` field of ` Problem ` responses with custom templates at the environment level.
558+ This is useful when the final URIs are not known at development time or may vary depending on deployment, enabling them
559+ to resolve to proper HTTP links dynamically.
560+
561+ Property that defines a template for overriding the ` "type" ` field in ` Problem ` responses. The value may contain special
562+ placeholders that will be replaced at runtime:
563+
564+ - ` {problem.type} ` — the original problem’s ` "type" ` value
565+ - ` {context.traceId} ` — the current request’s trace identifier (if available)
566+
567+ Defaults to ` null ` (no override applied). This can be used to unify or enrich problem type URIs across the application.
568+
569+ > For example, if setting ` type ` in your exception to ` problems/validation ` and:
570+ >
571+ > ``` properties
572+ > problem4j.type-override =https://errors.example.com/{problem.type}
573+ > ```
574+ >
575+ > the post processor will change `" type" ` value to `" https://errors.example.com/problems/validation`.
550576
551577### `problem4j.instance-override`
552578
553- Property that defines a template for overriding the ` "instance" ` field in ` Problem ` responses.The value may contain the
554- special placeholder ` {traceId} ` , which will be replaced at runtime with the trace identifier from the current request (
555- see [ ` problem4j.tracing-header-name ` ] ( #problem4jtracing-header-name ) ). Defaults to ` null ` (no override applied).
579+ This property allow overriding the `" instance" ` field of `Problem` responses with custom templates at the environment
580+ level. This is useful when the final URIs are not known at development time or may vary depending on deployment,
581+ enabling them to resolve to proper HTTP links dynamically.
582+
583+ Property that defines a template for overriding the `" instance" ` field in `Problem` responses. The value may contain
584+ special placeholders that will be replaced at runtime:
585+
586+ - `{problem.instance}` — the original problem’s `" instance" ` value
587+ - `{context.traceId}` — the current request’s trace identifier (if available)
588+
589+ Defaults to `null` (no override applied). This is useful for controlling how problem instances are represented in your
590+ API responses, even without tracing enabled.
556591
557- For example, by assigning ` problem4j.instance-override=/error-instances/{traceId} ` , with tracing enabled, each ` Problem `
558- response will have ` "instance" ` field matching to that format (e.g. ` "/error-instances/WQ1tbs12rtSD" ` ).
592+ > For example if not assigning `instance` at all in your exceptions and:
593+ >
594+ > ```properties
595+ > problem4j.instance-override=/errors/{context.traceId}
596+ > ```
597+ >
598+ > the post processor will change `" instance" ` value to `" /errors/WQ1tbs12rtSD" `.
599+ >
600+ > For using `{problem.instance}` placeholder, the `instance` field will behave similarly to `type-override`.
559601
560602### `problem4j.resolver-caching.enabled`
561603
0 commit comments