Close

Customizing Spring default HandlerExceptionResolvers functionality

[Last Updated: Feb 9, 2017]

Spring MVC 

This example demonstrates how to modify Spring default HandlerExceptionResolvers functionality.

The use case we are going to use is: we will map Spring internal exceptions to a custom error page. By default, Spring internal exceptions are processed by DefaultHandlerExceptionResolver. This example will demonstrate, how to selectively modify the default behavior. We will use SimpleMappingExceptionResolver to achieve the desired results.

Prerequisite

Ordering and customization of default HandlerExceptionResolvers


Creating SimpleMappingExceptionResolver and registering as a bean

@EnableWebMvc
@ComponentScan("com.logicbig.example")
public class AppConfig {

  @Bean
  HandlerExceptionResolver customExceptionResolver () {
      SimpleMappingExceptionResolver s = new SimpleMappingExceptionResolver();
      Properties p = new Properties();
      //mapping spring internal error NoHandlerFoundException to a view name.
      p.setProperty(NoHandlerFoundException.class.getName(), "error-page");
      s.setExceptionMappings(p);
      //uncomment following line if we want to send code other than default 200
      //s.addStatusCode("error-page", HttpStatus.NOT_FOUND.value());

      //This resolver will be processed before default ones
      s.setOrder(Ordered.HIGHEST_PRECEDENCE);
      return s;
  }

  @Bean
  public ViewResolver viewResolver () {
      InternalResourceViewResolver viewResolver =
                new InternalResourceViewResolver();
      viewResolver.setPrefix("/WEB-INF/views/");
      viewResolver.setSuffix(".jsp");
      return viewResolver;
  }
}

The above SimpleMappingExceptionResolver maps Spring internal NoHandlerFoundException to a custom page, the rest of the default functionality will be unchanged.


WebApplicationInitializer implementation

public class AppInitializer extends
        AbstractAnnotationConfigDispatcherServletInitializer {

  @Override
  protected Class<?>[] getRootConfigClasses () {
      return new Class<?>[]{AppConfig.class};
  }

  @Override
  protected Class<?>[] getServletConfigClasses () {
      return null;
  }

  @Override
  protected String[] getServletMappings () {
      return new String[]{"/"};
  }

  @Override
  protected FrameworkServlet createDispatcherServlet (WebApplicationContext wac) {
      DispatcherServlet ds = new DispatcherServlet(wac);
      //setting this flag to true will throw NoHandlerFoundException instead of 404 page
      ds.setThrowExceptionIfNoHandlerFound(true);
      return ds;
  }
}

What is throwExceptionIfNoHandlerFound?

The exception NoHandlerFoundException will only be thrown if this flag of DispatcherServlet is set to true. We are doing that by using DispatcherServlet#setThrowExceptionIfNoHandlerFound(true). By default this flag is false.


src/main/webapp/WEB-INF/views/error-page.jsp

D:\LogicBig\example-projects\spring-mvc\default-exception-resolver-customization\src\main\webapp\WEB-INF\views\error-page.jsp

The Controller

@Controller
public class ExampleController {

  /**
   * This will throw MissingPathVariableException with response code 500
   */
  @RequestMapping("/test/{id}")
  @ResponseBody
  public String handleRequest (@PathVariable("testId") String id) {
     return "id: "+id;
  }

  /**
   * The exception should be processed by @ExceptionHandler method
   */
  @RequestMapping("/test")
  public String handleRequest2 () throws Exception {
      throw new OperationNotSupportedException();
  }


  @ExceptionHandler
  @ResponseBody
  public String handleException (OperationNotSupportedException b) {
      return "from @ExceptionHandler method: " + b ;
  }
}

Run embedded tomcat

mvn tomcat7:run-war

output

URI: /test/{id}

This should throw MissingPathVariableException, which is not mapped by our SimpleMappingExceptionResolver.

The above exception is handled by DefaultHandlerExceptionResolver.


URI: /test

This should invoke handleException(..) method of our controller. This method is annotated with @ExceptionHandler and has parameter of the matching exception.

This shows that ExceptionHandlerExceptionResolver is processed as expected.


Other URIs

Other URIs, would normally, return default tomcat 404 error page. In our case, we have set DispatcherServlet to throw NoHandlerFoundException, which is mapped to "error-page" as set by our SimpleMappingExceptionResolver.

Let's see what's the response status code in HTTPie :

If SimpleMappingExceptionResolver doesn't set any status code explicitly then the code 200 is returned. If we want to return 404 instead, then we can use SimpleMappingExceptionResolver#addStatusCode("error-page", 404);



Example Project

Dependencies and Technologies Used:

  • spring-webmvc 4.3.5.RELEASE: Spring Web MVC.
  • javax.servlet-api 3.0.1 Java Servlet API
  • JDK 1.8
  • Maven 3.3.9

default-exception-resolver-customization Select All Download
  • default-exception-resolver-customization
    • src
      • main
        • java
          • com
            • logicbig
              • example
                • AppConfig.java
          • webapp
            • WEB-INF
              • views

    See Also