Spring MVC Exception Handler
Comments: 7In previous version of Spring Framework to handle exception we used HandlerExceptionResolver interface. Spring also provides simple implementations which was suitable in most of cases. Since 3.0 version we have few additional exception resolvers plus we can use annotation to specify our exception handler methods or classes without implementing HandleExceptionResolver interface.
- AnnotationMethodHandlerExceptionResolver (new in 3.0)
- ResponseStatusExceptionResolver (new in 3.0)
- DefaultHandlerExceptionResolver (new in 3.0)
- SimpleMappingExceptionResolver
SimpleMappingExceptionResolver
Should be configured in XML, there are few properties which drives this resolver behaviors.
- defaultErrorView -> this view name will be returned if no mapping will be found.
- defaultStatusCode -> once the view name was resolved if the view hasn’t status code the defaultStatusCode will be applied.
- statusCodes -> Map with “view name” to “status code” mapping.
- exceptionAttribute -> the name of attribute where exception is hold by default “exception” is used.
- exceptionMappings -> Properties which maps Exception “class name” to “view name”. Watch out as you can easily maps more than you want, this is because only String.contains is checked, so a=viewName mapping will catch all exception with “a” in the name.
Another thing to consider is that if you provide deep Exception hierarchy (n) and you provide a lot of exception mapping (m), you will end up with O(n*m) lookup algorithm. It may seem not problem, but if somebody spots that (Error page which render time is quite long), than it may be used with DDOS to increase load on ours machines.
DefaultHandlerExceptionResolver
First at all it has pageNotFound logger which is org.springframework.web.servlet.PageNotFound logger category, second it decides what to do depending on exception type, it is base class to extend when we want change default behavior:
- NoSuchRequestHandlingMethodException : no request handler method was found by default it sends 404 error. Override handleNoSuchRequestHandlingMethod.
- HttpRequestMethodNotSupportedException : no request handler method was found for the particular HTTP request method by default 405 error.Override handleHttpRequestMethodNotSupported.
- HttpMediaTypeNotSupportedException : no HttpMessageConverter were found for the PUT or POSTed content by default 415 error. Override handleHttpMediaTypeNotSupported.
- HttpMediaTypeNotAcceptableException : no HttpMessageConverter were found that were acceptable for the client (Accept header) by default 406 error. Override handleHttpMediaTypeNotAcceptable.
- MissingServletRequestParameterException : required parameter is missing by default 400 error. Override handleMissingServletRequestParameter.
- ConversionNotSupportedException : WebDataBinder conversion cannot occur by default 500 error. Override handleConversionNotSupported.
- TypeMismatchException : WebDataBinder conversion error occurs by default 400. Override handleTypeMismatch.
- HttpMessageNotReadableException : HttpMessageConverter cannot read from HTTP request by default 400 error. Override handleHttpMessageNotReadable.
- HttpMessageNotWritableException : HttpMessageConverter cannot write to HTTP response by default 500 error. Override handleHttpMessageNotWritable.
ResponseStatusExceptionResolver
This resolver allows us to use @ResponseStatus annotation. If we annotate our Exception with @ResponseStatus annotation than the response will get status code from annotation.
- ResponseStatus.value as status code (it is HttpStatus enum)
- ResponseStatus.reason as reason or default HttpResponse reason if not set.
AnnotationMethodHandlerExceptionResolver
Last but not least, and from my point of view this resolver is the most important. This exception resolver allows us to use @ExceptionHandler annotation, every method annotated by @ExceptionHandler will become exception handler. As parameters @ExceptionHandler need an array of Throwable. We also should use @ResponseStatus to indicate status code.
The method signatures possibilities are vary so see documentation to get all the proper combinations of parameters and return types.
The idea is pretty simple, for all the ExceptionHandler.value exception the exception -> Method handler is created, when Exception happens Method will be invoked.
Conclusions
Since 3.0 we rather has no need to setup handlers by ourself, the most useful way is to use @ExceptionHandler annotation. By default DispatcherServlet will setup AnnotationMethodHandlerExceptionResolver, ResponseStatusExceptionResolver and DefaultHandlerExceptionResolver as handlers resolvers. So we are ready to start with annotation based approach.
My approach is that I try to create moduleExceptionHandler class which has all methods annotated by @ExceptionHandler (except utility methods of course) and I always annotate them by @ResponseStatus as well. The methods parameters and return type vary depending on my needs. It a little bit central approach but it avoids problem with more than one handler per Exception.
Comments
pedro
@Benton999: Don’t know if understand correctly. If you want to order different *ExceptionResolver-s than you can do this by using setOrder (I didn’t check if that work regarding Exception resolver, but I’ve used Ordered interface in different spring areas and it worked).
If you are investing in framework probably implementing own ExceptionResolver and putting go on top setOrder(Integer.MAX_VALUE) will allow you to do whatever you want. If your framework is public, please share with link to the code
And I’ve just publish the code example
pedro
Hi all, sorry that you have to wait for such long time, the code is ready to clone. If there are any problems fill free to contact and push me 😉
Benton999
Pedro,
Is there any way to give priority to the in-Controller Exception Handling methods over the general Exception Handling Class you’ve just described?
I’d be great to let the developers implement their own methods, and just in case they forget to do so, include an Exception Handling Class in the Enterprise Framework I’m Developing.
Any suggestions?
PD: A code example would make this post great!
Priit
It appears that this cannot be done because ExceptionHandler annotated method is triggered only when the same controller class causes the exception.
Source: http://stackoverflow.com/questions/3230358/spring-3-create-exceptionhandler-for-nosuchrequesthandlingmethodexception/3230559#3230559
pedro
OK, code will just arrived in few days. I’m using blogo for posting and this comments just disappers.
Heikki
Hi Pedro, Would really appreciate if you could publish some code regarding centralized exception management using @ExceptionHander annotation. I have been struggling with very problem past view days, not happy distrusting exception handling all over controllers.
Marco
Pedro, what about an “Hello World” example, with some Spring 3.0 and annotations for Exception handlers? I’d find it very useful.