Improve Your Spring REST API, Part II

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.

Edit

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.

Goal

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:

Spring Classes

Before getting to work, there are a couple of Spring classes that we need to get acquainted with:

DefaultHandlerExceptionResolver

Like many other Spring classes, the DefaultHandlerExceptionResolver has a long and rather self explanatory name. Its purpose as quoted from the javadoc:

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.

AnnotationMethodHandlerExceptionResolver

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.

Custom HandlerExceptionResolver

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 ErrorMessageHandlerExceptionResolver:

Implementation Comments

  • The setOrder() method is called by the constructor. The AbstractHandlerExceptionResolver implements the Ordered interface that Spring uses to prioritize between different exception handlers if there is more than one implementation in the current application context.
  • The setErrorMessageFactories() is where the different ErrorMessageFactorys are supplied.
  • The setMessageConverters() is used to provide the necessary HttpMessageConverters needed for the serialization of the ErrorMessages.

ErrorMessageFactory implementations

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 MethodArgumentNotValidExceptionErrorMessageFactory:

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.

Putting it together

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 @Component and @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.

Future Improvements

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.

Dependencies

  • Spring 3.1.2.RELEASE
  • jackson-databind 2.0.5

References

3 Responses to “Improve Your Spring REST API, Part II”

  1. [...] searching the web and found amongst many results some interesting such as this and that this and that . Although those websites contain detailed information, I wanted to dive deep into the subject and [...]

  2. Pap says:

    Hi Mattias,

    Could you please provide an application based on Spring 3.2 and REST services with the following
    1) REST service to expose some data in XML and Json format
    2) Secure the REST service using SSL certificates or any other mechanism
    3)Exposing a Javabean or ArrayList in XML
    4) How to consume the REST service if it contains an object like ArrayList or ResultSet etc

    I have experience consuming REST service(using Ajax calls or Apache Abdera etc) but never have created one!

    If you dont have time to do this then if you can spend some time and guide me then I would be happy to develop this as well and you can post it in your site! And I am sure there are lot of guys learning REST services will appreciate this a lot!

    Thanks!

Leave a Reply