Spring MVC - Ordering and customization of default HandlerExceptionResolvers

[Updated: Dec 7, 2017, Created: Jan 21, 2017]

In previous tutorials we have gone through various implementations of HandlerExceptionResolver. Here's a quick review:

HandlerExceptionResolver
Implementation
Active
by default
Purpose
DefaultHandlerExceptionResolver Yes It translates Spring internal exception to specific HTTP status codes.
ExceptionHandlerExceptionResolver Yes Allows to use @ExceptionHandler on the controller's methods. If an exception is thrown then one of these methods are called with matching exception type.
ResponseStatusExceptionResolver Yes Allows to use @ResponseStatus on exception classes so that unhandled exception can be returned with a specified HTTP status code.
SimpleMappingExceptionResolver No Allows to map 'exception types' to 'view names', to map 'view names' to 'HTTP status code', setting default error view name and setting default HTTP status code.
HandlerExceptionResolverComposite N/A If an exception is thrown, this resolver delegates the exception handling to a list of other HandlerExceptionResolvers.

In this tutorial we are going to understand how DispatcherServlet processes the default and application registered HandlerExceptionResolvers. We will also learn how to customize the default settings.


The processing order of HandlerExceptionResolvers

DispatcherServlet uses following method to sort the list of default and application registered HandlerExceptionResolvers:

AnnotationAwareOrderComparator.sort(this.handlerExceptionResolvers);

AnnotationAwareOrderComparator is an extension of OrderComparator, which sorts a collection elements in ascending order of the element's order value. The order value is provided by Ordered, an interface which can optionally be implemented by the collection elements. Any element that does not implement this interface is implicitly assigned a value of Ordered.LOWEST_PRECEDENCE (=Integer.MAX_VALUE), thus ending up at the end of the collection. Objects that have the same order values are sorted in arbitrary ordering with other same valued elements.

HandlerExceptionResolverComposite's delegators are not sorted in any order, their original list order is maintained.

The default order

Spring MVC framework, initializes the default exception resolvers in WebMvcConfigurationSupport, the main class behind the MVC Java config and @EnableWebMvc.

To have a good understanding following is a snippet where the resolvers are registered as a bean:

public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
 ................
 @Bean
 public HandlerExceptionResolver handlerExceptionResolver() {
  List<HandlerExceptionResolver> exceptionResolvers = new ArrayList<HandlerExceptionResolver>();
  configureHandlerExceptionResolvers(exceptionResolvers);
  if (exceptionResolvers.isEmpty()) {
   addDefaultHandlerExceptionResolvers(exceptionResolvers);
  }
  extendHandlerExceptionResolvers(exceptionResolvers);
  HandlerExceptionResolverComposite composite = new HandlerExceptionResolverComposite();
  composite.setOrder(0);
  composite.setExceptionResolvers(exceptionResolvers);
  return composite;
	}
............
}

By default, only one HandlerExceptionResolverComposite is registered with order value '0' and having the following delegators in exactly the same order:

ExceptionHandlerExceptionResolver
ResponseStatusExceptionResolver
DefaultHandlerExceptionResolver

DispatcherServlet keeps a list of the the above default HandlerExceptionResolverComposite plus the HandlerExceptionResolvers registered by the application client. This list is sorted as described above.

If during processing a request an exception is thrown, DispatcherServlet processes the exception by iterating through the list of resolvers. The first resolver to return a non-null value of ModelAndView from HandlerExceptionResolver#resolveException call, will win. If none of the resolvers handle the exception, it goes unhandled.

Note that when using older ways of configuration than @EnableWebMvc, AnnotationMethodHandlerExceptionResolver (deprecated) is registered instead of ExceptionHandlerExceptionResolver.


The Order of application registered HandlerExceptionResolvers

If application client registers an 'Ordered' HandlerExceptionResolver with order value greater than 0, it will be processed after the default resolver, otherwise before the default resolver. If the application resolver doesn't implement 'Ordered' interface then it will be process at the very end.

Also an application client can register multiple HandlerExceptionResolvers


Replacing the default resolvers

In above WebMvcConfigurationSupport snippet, the default HandlerExceptionResolver is registered with name 'handlerExceptionResolver' (the factory method handlerExceptionResolver() is used as bean name unless some other name is used as @Bean('beanName)). If we register a HandlerExceptionResolver bean with exactly the same name then that will override the default one.

Another similar way to replace default exception resolver is: to use DispatcherServlet#setDetectAllHandlerExceptionResolvers(false) and register exactly one bean with name DispatcherServlet#HANDLER_EXCEPTION_RESOLVER_BEAN_NAME. This method doesn't process the HandlerExceptionResolver beans with names other than this name, so we cannot register multiple HandlerExceptionResolver.


Examples

Customizing Spring default HandlerExceptionResolvers functionality
Replacing Spring default HandlerExceptionResolvers


See Also