Spring MVC - Exception to view mapping using SimpleMappingExceptionResolver

[Updated: Sep 2, 2017, Created: Jan 18, 2017]
java.lang.ObjectObjectorg.springframework.web.servlet.handler.AbstractHandlerExceptionResolverAbstractHandlerExceptionResolverorg.springframework.web.servlet.HandlerExceptionResolverHandlerExceptionResolverorg.springframework.core.OrderedOrderedorg.springframework.web.servlet.handler.SimpleMappingExceptionResolverSimpleMappingExceptionResolverLogicBig

SimpleMappingExceptionResolver is an implementation of HandlerExceptionResolver. It allows us to configure following parameters:

  • mapping exception class names to view names.
  • mapping view names to response status codes. It is done by using HttpServletResponse#setStatus(statusCode) method internally.
  • specifying a default exception view.
  • specifying a default response status code.

If interested, check out doResolveException() method of SimpleMappingExceptionResolver.java.


Example

JavaConfig class

Here we are going to register SimpleMappingExceptionResolver as a bean.

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

    @Bean
    HandlerExceptionResolver errorHandler () {
        SimpleMappingExceptionResolver s =
                  new SimpleMappingExceptionResolver();

        //exception to view name mapping
        Properties p = new Properties();
        p.setProperty(NullPointerException.class.getName(), "npeView");
        p.setProperty(OrderIdNotValidException.class.getName(),
                      "OrderIdNotValidView");
        s.setExceptionMappings(p);

        //mapping status code with view response.
        s.addStatusCode("npeView", 404);

        //setting default error view
        s.setDefaultErrorView("defaultErrorView");
        //setting default status code
        s.setDefaultStatusCode(400);

        return s;
    }

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

The Controller

@RestController
public class ExampleController {

    @Autowired
    private DataService dataService;

    @RequestMapping("/order/{orderId}")
    public String handleRequest (@PathVariable("orderId") String orderId) {
        return dataService.getOrderDetail(orderId);
    }

    @RequestMapping("/data/{id}")
    public String testHandler (@PathVariable("id") String id) {
        return dataService.getData(id);
    }

    @RequestMapping("/test")
    public void testHandler2 () {
       throw new RuntimeException("test exception");
    }
}
@Repository
public class DataService {
    private Map<String, Object> testData = new HashMap<>();
    private Map<Integer, String> testOrders = new HashMap<>();

    public DataService () {
        testData.put("1", "this is test data");
        testOrders.put(1, "Order 1");
        testOrders.put(2, "Order 2");
    }

    public String getData (String id) {
        //we purposely created NPE scenario for demo
        //only id=1 will return test data
        return testData.get(id).toString();
    }

    public String getOrderDetail (String orderId) {
        try {
            //only an integer is valid for order id
            int i = Integer.parseInt(orderId);
            String s = testOrders.get(i);
            return s == null ? "Empty Order" : s;
        } catch (NumberFormatException e) {
            throw new OrderIdNotValidException(
                      "Order id is not valid: " + orderId);
        }
    }
}

In above DataService class, we purposely created error scenarios.

public class OrderIdNotValidException extends RuntimeException {

    public OrderIdNotValidException (String message) {
        super(message);
    }
}

JSP pages

src/main/webapp/WEB-INF/views/defaultErrorView.jsp
<%@ page language="java"
    contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>

<html>
<body>
<h3>This is default exception page</h3>
 <p>Exception: <b>${exception}</b></p>

</body>
</html>

Note that, in above JSP page, we are using ${exception} place holder for the exception object. SimpleMappingExceptionResolver, by default, uses the Model attribute, "exception", mapped to the exception object. This default attribute name can be changed by using:
SimpleMappingExceptionResolver #setExceptionAttribute(String exceptionAttribute)

src/main/webapp/WEB-INF/views/OrderIdNotValidView.jsp
<%@ page language="java"
    contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>

<html>
<body>
<h4>Not a valid Order Id</h3>
<p>The provided order Id is not valid:  ${orderId}</p>
</body>
</html>
src/main/webapp/WEB-INF/views/npeView.jsp
<%@ page language="java"
    contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>

<html>
<body>
<h4>Data not found</h3>
<p>No data found for id ${id}</p>
</body>
</html>


Running embedded tomcat

 mvn clean install tomcat7:run-war

Output

We are going to use HTTPie to test output. HTTPie is a command line http client. It shows status code , headers and raw body content. If interested, checkout the tutorial to learn more about HTTPie.

Testing: /order/{orderId}

According to our DataService logic, only an integer is valid order id. Invalid order id will throw OrderIdNotValidException, which we mapped to OrderIdNotValidView.jsp in our SimpleMappingExceptionResolver bean.



Testing: /data/{id}

In DataService#getData(), only id=1 will return the data, others will throw NullPointerException. This exception is mapped to npeView.jsp. We also mapped this view with response status code 404:


Testing: /test

The mapped handler is throwing RuntimeException, which is not mapped to any view in our SimpleMappingExceptionResolver bean. In that case default error view will be shown and default status code will be returned in response:



Other URIs

Other URIs, which are not mapped to any handler will give tomcat 404 page.


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

Simple Mapping Exception Resolver Example Select All Download
  • simple-mapping-exception-resolver
    • src
      • main
        • java
          • com
            • logicbig
              • example
        • webapp
          • WEB-INF
            • views

See Also