Showing posts with label Exception. Show all posts
Showing posts with label Exception. Show all posts

Tuesday, 6 November 2012

Spring MVC Error Handling

This post describes the different techniques to perform error handling in Spring MVC 3. The code is available on GitHub in the Spring-MVC-Error-Handling directory. It is based on the Spring MVC With Annotations examples.

Handling Exceptions Before Spring 3

Before Spring 3, exceptions were handled with HandlerExceptionResolvers. This interface defines a single method:
ModelAndView resolveException(
  HttpServletRequest request,
  HttpServletResponse response,
  Object handler,
  Exception ex)
Notice it returns a ModelAndView object. Therefore, encountering an error meant being forwarded to a special page. However, this method is not suited for REST Ajax calls to JSONs (for example). In this case, we do not want to return a page, and we may want to return a specific HTTP status code. A solution, described further, is available.

For the sake of this example, two fake CustomizedException1 and CustomizedException2 exceptions have been created. To map customized exceptions to views, one could (and can still) use a SimpleMappingExceptionResolver:
SimpleMappingExceptionResolver getSimpleMappingExceptionResolver() {

    SimpleMappingExceptionResolver result
        = new SimpleMappingExceptionResolver();

    // Setting customized exception mappings
    Properties p = new Properties();
    p.put(CustomizedException1.class.getName(), "Errors/Exception1");
    result.setExceptionMappings(p);

    // Unmapped exceptions will be directed there
    result.setDefaultErrorView("Errors/Default");

    // Setting a default HTTP status code
    result.setDefaultStatusCode(HttpStatus.BAD_REQUEST.value());

    return result;

}
We map CustomizedException1 to the Errors/Exception1 JSP page (view). We also set a default error view for unmapped exception, namely CustomizedException2 in this example. We also set a default HTTP status code.

Here is the Exception1 JSP page, the default page is similar:
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!doctype html>
<html lang="en">
<head>
  <meta http-equiv="Content-Type" content="text/html;" charset=UTF-8">
  <title>Welcome To Exception I !!!</title>
</head>
<body>
    <h1>Welcome To Exception I !!!</h1>
    Exception special message:<
    ${exception.specialMsg}
    <a href="<c:url value='/'/>">Home</a>
</body>
</html>
We also create a dummy error controller to help triggering these exceptions:
@Controller
public class TriggeringErrorsController {

    @RequestMapping(value = "/throwCustomizedException1")
    public ModelAndView throwCustomizedException1(
        HttpServletRequest request,HttpServletResponse response)
            throws CustomizedException1 {

        throw new CustomizedException1(
            "Houston, we have a problem!");
    }

    @RequestMapping(value = "/throwCustomizedException2")
    public ModelAndView throwCustomizedException2(
        HttpServletRequest request,HttpServletResponse response)
            throws CustomizedException2 {

        throw new CustomizedException2(
            "Something happened on the way to heaven!");
    }

    ...

}
Before Spring 3, one would declare a SimpleMappingExceptionResolver as a @Bean in web.xml. However, we will use a HandlerExceptionResolverComposite which we will describe later.

We also configure a target page for HTTP status codes in web.xml, which is an other way to deal with issues:
<error-page>
    <error-code>404</error-code>
    <location>/WEB-INF/pages/Errors/My404.jsp</location>
</error-page>

What Is New Since Spring 3.X?

The @ResponseStatus annotation is a new mean to set a Http status code when a method is invoked. These are handled by the ResponseStatusExceptionResolver. The @ExceptionHandler annotation facilitates the handling of exceptions in Spring. Such annotations are processed by the AnnotationMethodHandlerExceptionResolver.

The following illustrates how these annotations can be used to set an HTTP status code to the response when our customized exception is triggered. The message is returned in the response's body:
@Controller
public class TriggeringErrorsController {

    ...

    @ExceptionHandler(Customized4ExceptionHandler.class)
    @ResponseStatus(value=HttpStatus.BAD_REQUEST)
    @ResponseBody
    public String handleCustomized4Exception(
        Customized4ExceptionHandler ex) {

        return ex.getSpecialMsg();

    }

    @RequestMapping(value = "/throwCustomized4ExceptionHandler")
    public ModelAndView throwCustomized4ExceptionHandler(

        HttpServletRequest request,HttpServletResponse response)
            throws Customized4ExceptionHandler {

        throw new Customized4ExceptionHandler("S.O.S !!!!");

    }

}
On the user side, if one uses an Ajax call, the error can be retrieved with the following (we are using JQuery):
$.ajax({
    type: 'GET',
    url:  prefix + "/throwCustomized4ExceptionHandler",
    async: true,
    success: function(result) {
        alert('Unexpected success !!!');
    },
    error: function(jqXHR, textStatus, errorThrown) {
        alert(jqXHR.status + " " + jqXHR.responseText);
    }
});
Some people using Ajax like to return a JSON with the error code and some message to handle exceptions. I find it overkill. A simple error number with a message keeps it simple.

Since we are using several resolvers, we need a composite resolver (as mentioned earlier):
@Configuration
public class ErrorHandling {

    ...

    @Bean
    HandlerExceptionResolverComposite getHandlerExceptionResolverComposite() {

        HandlerExceptionResolverComposite result
            = new HandlerExceptionResolverComposite();

        List<HandlerExceptionResolver> l
            = new ArrayList<HandlerExceptionResolver>();

        l.add(new AnnotationMethodHandlerExceptionResolver());
        l.add(new ResponseStatusExceptionResolver());
        l.add(getSimpleMappingExceptionResolver());
        l.add(new DefaultHandlerExceptionResolver());

        result.setExceptionResolvers(l);

        return result;

}
The DefaultHandlerExceptionResolver resolves standard Spring exceptions and translates them to corresponding HTTP status codes.

Running The Example

Once compiled, the example can be run with mvn tomcat:run. Then, browse:

  http://localhost:8585/spring-mvc-error-handling/

The main page will look like this:

Spring MVC Error Handling

If you click on the Exception 1 link, the following page will display:

Spring MVC Exception Handling

If you click on the Exception 2 link, the following page will display:


If you click on the Exception Handler button, a pop-up will be displayed:

Spring MVC Exception Handling Pop-Up

These techniques are enough to cover error handling in Spring.

More Spring related posts here.

Saturday, 28 July 2012

About Using System.Exit() in Try Catch Finally Java Statements

This post is an attempt at summarizing issues around using the Java system.exit() statements inside try {...} catch (...) {...} finally {...} statements.

We will use the following piece of code:
public class TryCatchFinallySystemExit {

  public static void main(String[] args) {

    System.setSecurityManager(new SecurityManager() {

      @Override
      public void checkPermission(Permission perm) { }

      @Override
      public void checkExit(int status) {
        // throw new SecurityException();
      }

    });

    System.out.println("Before Check");
    check();
    System.out.println("After Check");

  }

  public static void check() {

    try {

      System.out.println("Before System.exit(-1)");
      System.exit(-1);
      System.out.println("After System.exit(-1)");

    } catch(Throwable t) {

      System.out.println("Before System.exit(-2)");
      System.exit(-2);
      System.out.println("After System.exit(-2)");

    } finally {

      System.out.println("Before System.exit(-3)");
      System.exit(-3);
      System.out.println("After System.exit(-3)");

    }

    System.out.println("After try statement");

  }

}

The main method implements a SecurityManager, then calls the check() method. If we run this application as is, the output is the following:

Before Check
Before System.exit(-1)

We can conclude that:
  • System.exit(-1) is the last statement excuted.
  • Catch and Finally statements are not called.
  • The check() method does not return.

If we uncomment the throw new SecurityException(); and execute the application again, we get:

Before Check
Before System.exit(-1)
Before System.exit(-2)
Before System.exit(-3)

We can conclude that:
  • The SecurityException get the catch and finally statements to be executed.
  • Statements after System.exit() statements are not executed.
  • The check() method does not return.

For return, continue and break statements in try statements, see this post.

Disclaimer: this post contains information from personal notes and information available on StackOverflow.com.