1

In a spring boot rest controller based on reactive framework, how to configure, at the global level (similar to the global exception handler in spring mvc), the error response status according to the exception type thrown within the application still keeping the json error generated by spring boot?

for instance if there is an IllegalArgumentException thrown, the response would be:

HTTP/1.1 400 Bad Request
Content-Type: application/json
Content-Length: 191

{
    "timestamp": "2023-04-05T06:52:30.521+00:00",
    "path": "request/path",
    "status": 400,
    "error": "Bad Request",
    "requestId": "876c0e0b-1"
}

instead of the default:

HTTP/1.1 500 Internal Server Error
Content-Type: application/json
Content-Length: 191

{
    "timestamp": "2023-04-05T06:52:30.521+00:00",
    "path": "request/path",
    "status": 500,
    "error": "Internal Server Error",
    "requestId": "876c0e0b-1"
}

Thanks

vivi
  • 163
  • 13
  • https://docs.spring.io/spring-framework/docs/current/reference/html/web-reactive.html#webflux-ann-controller-exceptions – Toerktumlare Apr 04 '23 at 23:45
  • Thanks, it responds to the initial question. What if I would like to keep the json error generated by spring boot, just changing the status according to the exception type? – vivi Apr 05 '23 at 07:04

1 Answers1

1

to keep the json error generated by spring boot

best (i think):

Extend ResponseEntityExceptionHandler

like :

@ControllerAdvice
class MyAdvice extends ResponseEntityExceptionHandler {

    // ...
}

(this is aware of your application.properties ..esp. spring.webflux.problemdetails.enabled)

To custom handle "common exceptions"

just changing the status according to the exception type

Override the according handleXXXException method, in this(400) scenario e.g. (handleResponseStatusException):

@ControllerAdvice
class MyAdvice extends ResponseEntityExceptionHandler {

    @Override
    protected Mono<ResponseEntity<Object>> handleResponseStatusException(
            ResponseStatusException ex, HttpHeaders headers, HttpStatusCode status,
            ServerWebExchange exchange) {
        // do what you need/like:
        HttpStatusCode myNewStatus;
        /*
       
        switch (status.value()) { // alternatively: if (status.isXXX()) [else if .. else ..]
           ...
        }*/
        return /*super.*/handleExceptionInternal(ex, null, headers, myNewStatus, exchange);
    }
}

To commonly handle "custom exceptions"

best:

  1. Let your "custom exception" extend ErrorResponseException:

    class MyException extends ErrorResponseException {
    
      public MyException(HttpStatusCode status) { // we need to override (at least 1) super constructor!
        super(status);
      }
    }
    
  2. Handle it with a custom exception handler (reusing parent methods;):

    @ControllerAdvice
    class MyAdvice extends ResponseEntityExceptionHandler {
      // ...
      @ExceptionHandler({MyException.class})
      public Mono<ResponseEntity<Object>> handleMyException(MyException ex, ServerWebExchange exchange) {
        return handleExceptionInternal(ex, null, ex.getHeaders(), ex.getStatusCode(), exchange);
      }
      // ...
    }
    

For details, best: "browse" the javadoc, source code, "hierarchy structure" & "usages" of the mentioned classes.

The (springboot-webflux) default @ControllerAdvice/ResponseEntityExceptionHandler is configured with org.springframework.boot.autoconfigure.web.reactive.ProblemDetailsExceptionHandler.

xerx593
  • 12,237
  • 5
  • 33
  • 64