In the previous blog post, I explained how a custom @ExceptionHandler can be used to return feedback to REST API clients when they are submitting erroneous requests. However, the suggested implementation does not scale, because an
@ExceptionHandler method is only applicable for a specific controller. In a real project, it is likely that we would like consistent error handling across multiple controllers. The easiest way to overcome this problem is to create a common super class that can be extended by all other controllers. To create a more generic solution to the problem, we can look under the hood of Spring itself and get inspired.
Feb 3rd, 2013: The
@ControllerAdvice and the
ResponseEntityExceptionHandler in the Spring 3.2 release effectively obsoletes the implementation below. Please read the updated solution in next blog unless you are stuck with an older version of Spring.
The intent of this blog post is to implement a custom HandlerExceptionResolver that in addition to the HTTP status codes also writes useful data to the response body when an exception occurs. The idea is to create a pluggable solution that generates error messages consistently by reusing the ErrorMessage class introduced in the previos blog post. The content of an error message depends on the specific exception and it should be derived by implementing a factory interface:
Before getting to work, there are a couple of Spring classes that we need to get acquainted with:
Default implementation of the HandlerExceptionResolver interface that resolves standard Spring exceptions and translates them to corresponding HTTP status codes.
This exception resolver is enabled by default in the org.springframework.web.servlet.DispatcherServlet.
Take a look at the implementation of its doResolveException() method available at GitHub. As can be seen, it delegates to the many
handle*() methods depending on the type of exception that occurs, and then the HTTP Status code is assigned accordingly. Both the
doResolveException() method and all
handle*() methods are
protected which means that here is an opportunity to extend the class and provide alternative implementations. This also suggests that any subclass should be specific about which handle methods to override, which makes it less suitable for a generic solution.
Have you ever wondered what makes a custom
@ExceptionHandler method tick? The implementation is handled by the AnnotationMethodHandlerExceptionResolver. In contrast to the previously mentioned
DefaultHandlerExceptionResolver, it is able to serialize return values annotated with the @ResponseBody into the HTTP response body, something that will be necessary for our project at hand. A closer look at the handleResponseBody() method at GitHub reveals the implementation details.
Another observation of the
DefaultHandlerExceptionResolver and the
AnnotationMethodHandlerExceptionResolver classes is that they extend the same parent class, namely the AbstractHandlerExceptionResolver. With this knowledge, we can implement a custom
setOrder()method is called by the constructor. The
AbstractHandlerExceptionResolverimplements the Ordered interface that Spring uses to prioritize between different exception handlers if there is more than one implementation in the current application context.
setErrorMessageFactories()is where the different
ErrorMessageFactorys are supplied.
setMessageConverters()is used to provide the necessary HttpMessageConverters needed for the serialization of the
Now, we create different implementations of the
ErrorMessageFactory interface for various exceptions. For example, the
@ExceptionHandler for the
MethodArgumentNotValidException that was implemented in the previous blog post can be implemented as an
Other examples include a HttpMediaTypeNotSupportedExceptionErrorMessageFactory for generating error messages for unsupported media types and a HttpMessageNotReadableExceptionErrorMessageFactory for cases when the reading of a request message body fails, e.g. due to a parse exception. These are just some examples, it is easy to implement more factories if necessary.
The last piece of the solution is to create a
WebApplicationContext in which the
ErrorMessageHandlerExceptionResolver bean, the
ErrorMessageFactory beans and the
HttpMessageConverters are wired together. Several options are available, e.g. Java based configuration, adding
@Autowire annotations (or their JSR-330 counterparts) to the provided snippets and let component scanning take care of the rest, or to use the more traditional XML based configuration. The choice is not different from any other Spring MVC project configuration, it is just a matter of personal preference.
The suggested solution is based on Spring 3.1, and it is very likely that the suggested solution will be obsoleted by the Spring 3.2 release. Spring has also recognized the advantages of returning a response body in conjunction with an HTTP error code. Issue SPR-8406 – Create separate handler stereotype for RESTful web services in the Spring Jira addresses the problem, a solution based on the new ResponseEntityExceptionHandler class and the new @ControllerAdvice annotation has been implemented and is available as part of the Spring 3.2 M2 release.