Lives in the UK. Likes blogging, cycling and eating lemon drizzle cake. Roger is a DZone MVB and is not an employee of DZone and has posted 143 posts at DZone. You can read more from them at their website. View Full User Profile

Spring 3 MVC Exception Handlers

02.13.2012
| 12692 views |
  • submit to reddit

The majority of the Spring 3 error handling sample code that I’ve come across only ever seems to give the simplest overview of its usage, yet how we handle errors is, some would say, more important than how the normal code works. This was borne out the other day when I came across a simple ‘GOTCHA’ in a Spring 2 error handler that brought a whole website down and almost killed the server, but more on that later.

Today’s blog examines the scenario of creating a simple Spring 3 servlet exception handler using the @ExceptionHandler annotation. Although you may have seen this before it provides me with a good place to start, and for this demonstration I’ve created a simple Spring 3 MVC webapp1 where the home page (home.jsp) makes requests to a flaky controller class that throws exceptions (ExceptionDemoController)

  /**
   * Whoops, throw an IOException
   */
  @RequestMapping(value = "/ioexception", method = RequestMethod.GET)
  public String throwIoException(Locale locale, Model model) throws IOException {

    logger.info("This will throw an IOExceptiom");

    boolean throwException = true;

    if (throwException) {
      throw new IOException("This is my IOException");
    }

    return "home";
  }
The flaky controller code above is the first step in generating an error. The idea is that it’s supposed to return the user to our home page, but in the mists of processing the user’s request it throws a simple IOException. Once thrown, the exception is caught by this method:

 
/**
   * Catch IOException and redirect to a 'personal' page
   */
  @ExceptionHandler(IOException.class)
  public ModelAndView handleIOException(IOException ex) {

    logger.info("handleIOException - Catching: " + ex.getClass().getSimpleName());
    return errorModelAndView(ex);
  }

  /**
   * Get the users details for the 'personal' page
   */
  private ModelAndView errorModelAndView(Exception ex) {
    ModelAndView modelAndView = new ModelAndView();
    modelAndView.setViewName("error");
    modelAndView.addObject("name", ex.getClass().getSimpleName());
    modelAndView.addObject("user", userDao.readUserName());

    return modelAndView;
  }
To set this up is really simple, all you need to do is to add:

  @ExceptionHandler(IOException.class)

… to a method signature, et voila you’re done ...and that’s the simple bit over with.

There are some points worth noting here: firstly, using

  @ExceptionHandler(IOException.class)

…will adhere to the usual contract for exception handling. This means that not only will the method above catch all IOExceptions, it’ll also catch all exceptions that are subclasses of IOException; hence, if my throwAnException(..) method threw a FileNotFoundException it’ll still be caught by my handleIOException(...) method.

Secondly, there is a very flexible, but ultimately limited, set of method signatures that you can use for exception handler methods. The full documentation for this is provided by Spring’s JavaDoc, but in summary you can devise a signature that contains any of the following input arguments in any order:
  • Exception or one of its subclasses
  • ServletRequest or HttpServletRequest
  • ServletResponse or HttpServletResponse
  • HttpSession
  • WebRequest or NativeWebRequest
  • Locale
  • InputStream or one of its subclasses to access the request’s content
  • OutputStream or one of its subclasses to access the response’s content
  • Reader or one of its subclasses
  • Writer or one of its subclasses

The method signature must also have one of the following return types:
  • ModelAndView
  • Model
  • Map
  • View
  • String - interpreted as a view name
  • void, but only if the method writes directly to the response object

All of which should be enough for any scenario under any circumstance.

Using @ExceptionHandler gives you the ability to perform fine grained exception handling that targets different error scenarios. In the case of the sample code, I create a new ModelAndView object and populate it with the user’s name in order to personally tell him/her that the system has lost their documents. Some may say that this is a limitation, as @ExceptionHandler is so fine-grained that you can only catch exceptions thrown by the controller that contains your @ExceptionHandler annotated method. I would disagree, if you want to catch exceptions thrown by multiple controllers in one place, then this technique is not for you and you should consider using a SimpleMappingExceptionResolver instead.

There’s lots to consider when implementing error handling such as: what happens if there’s an error in your error handler? Should you use coarse or fine grained exception handlers? What about setting the HTTP status code? So, my next few blogs will looking into error handling further, demonstrating how to assign multiple exception classes to a single @ExceptionHandler and how to combine the exception handler notation with @ResponseStatus to fine tune your server’s HTTP status code, and may be more...

  1. The full webapp sample is available at:

    git://github.com/roghughe/captaindebug.git
  2. See the Spring documentation for reference material.

 

From http://www.captaindebug.com/2012/02/spring-3-mvc-exception-handlers.html

Published at DZone with permission of Roger Hughes, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)