Some time ago, I wrote about how the error response of a Spring based REST API can be enhanced, in order to provide the clients with a better understanding of why a request error occurred. In the first post I explained how a server-side exception triggered by an incoming request can be translated into a generic ErrorMessage class, which in turn was serialized to the response body. In the second part, the solution was generalized, to prevent the @ExceptionHandler methods from being duplicated to all controllers. However, the release of Spring 3.2 last December provides a new feature which greatly simplifies the general solution.
The @ControllerAdvice is a new TYPE annotation that was added as part of the release. A class annotated with it will act as a global helper class for all controllers. In other words, any local, controller specific
@ExceptionHandler method that is moved from the
@Controller class to a class annotated with
@ControllerAdvice, will be applicable for the entire application. Consequently, all the boiler plate code that was created in the generic solution in my last post can be removed. The revisited solution can be as simple as:
The previous posts contained error handling examples of some Spring MVC exceptions, namely the
HttpMediaTypeNotSupportedException and the
HttpMessageNotReadableException. A corresponding Spring 3.2 based implementation can be found in the GlobalControllerExceptionHandler, or continue reading for yet another implementation.
The above example works well, but it can be hard to identify the Spring MVC specific exceptions to implement a common error response handling strategy for them. One way of overcoming this problem is to extend the ResponseEntityExceptionHandler class, which was also added to the Spring 3.2 release. Similarly to the DefaultHandlerExceptionResolver, it provides methods for handling the exceptions, but it allows the developer to specify ResponseEntitys as return values (as opposed to the ModelAndViews that are returned by the methods in the
DefaultHandlerExceptionResolver). The implementation is still straight forward, create a class, annotate it with the
@ControllerAdvice, extend the
ResponseEntityExceptionHandler class and override the methods with the exception types that you are interested in:
@ControllerAdviceannotation is an
@Component. As such, an annotated class will be registered as a Spring bean if the package in which it is located in is subject to component scanning.
@ControllerAdvicealso supports methods annotated with @InitBinder and @ModelAttribute.