In Spring you can set up "global" exception handler via @ControllerAdvice and @ExceptionHandler annotation. I'm trying to utilize this mechanism to have two global exception handlers:
RestControllerExceptionHandler
- which should return error responses as json for any controller annotated with@RestController
ControllerExceptionHandler
- which should print error message to the screen for any other controller (annottated with@Controller
)
The problem is that when I declare these two exception handlers spring always uses the ControllerExceptionHandler
and never RestControllerExceptionHandler
to handle the exception.
How to make this work ? BTW: I tried to use @Order annotation but this does not seem to work.
Here are my exception handlers:
// should handle all exception for classes annotated with
@ControllerAdvice(annotations = RestController.class)
public class RestControllerExceptionHandler {
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleUnexpectedException(Exception e) {
// below object should be serialized to json
ErrorResponse errorResponse = new ErrorResponse("asdasd");
return new ResponseEntity<ErrorResponse>(errorResponse, HttpStatus.INTERNAL_SERVER_ERROR);
}
// should handle exceptions for all the other controllers
@ControllerAdvice(annotations = Controller.class)
public class ControllerExceptionHandler {
@ExceptionHandler(Exception.class)
public ResponseEntity<String> handleUnexpectedException(Exception e) {
return new ResponseEntity<String>("Unexpected exception, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
}
When I remove ControllerExceptionHandler
than RestControllerExceptionHandler
is correctly called by spring (only for classes annotated with @RestController
).... but when I add ControllerExceptionHandler
than all goes via ControllerExceptionHandler
. Why?
After some deeper investigation it seems that the alphabetical order matters :/.
When I renamed my RestControllerExceptionHandler
to ARestControllerExceptionHandler
(which alphabetically precedes ControllerExceptionHandler
) all works as expected! ARestControllerExceptionHandler
correctly handles exceptions from RestControllers
and ControllerExceptionHandler
handles exception from other controllers.
I created a bug in spring for this: https://jira.spring.io/browse/SPR-15432
--- EDIT:
I received the answer for SPR-15432 where it is suggested that this case can be solved with @Order
(org.springframework.core.annotation.Order
) annotation or by implementing Ordered interface.
This did not work for me before, but it seems that I have imported wrong @Order
annotation. (from log4j2 instead of spring). After fixing this it works. Fixed version is following:
// should handle all exception for classes annotated with
@ControllerAdvice(annotations = RestController.class)
@Order(1) // NOTE: order 1 here
public class RestControllerExceptionHandler {
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleUnexpectedException(Exception e) {
// below object should be serialized to json
ErrorResponse errorResponse = new ErrorResponse("asdasd");
return new ResponseEntity<ErrorResponse>(errorResponse, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
// should handle exceptions for all the other controllers
@ControllerAdvice(annotations = Controller.class)
@Order(2) // NOTE: order 2 here
public class ControllerExceptionHandler {
@ExceptionHandler(Exception.class)
public ResponseEntity<String> handleUnexpectedException(Exception e) {
return new ResponseEntity<String>("Unexpected exception, HttpStatus.INTERNAL_SERVER_ERROR);
}
}