14
votes

I have a Spring MVC controller with some simple REST service requests. I would like to add some error handling when specific exceptions are thrown from my services, but I cannot get a handler method annotated with @ExceptionHandler to actually ever be called. Here is one service I am deliberately throwing an exception to try and get my handler method to take over. The handler method is never invoked and Spring just returns a 500 error to the calling client. Do you have any ideas on what I'm doing wrong?

@ExceptionHandler(IOException.class)
public ModelAndView handleIOException(IOException ex, HttpServletRequest request, HttpServletResponse response) {
    response.sendError(HttpServletResponse.SC_FORBIDDEN);
    System.out.println("It worked!");
    return new ModelAndView();
}

@RequestMapping(value = "/json/remove-service/{id}", method = RequestMethod.DELETE)
public void remove(@PathVariable("id") Long id) throws IOException {
    throw new IOException("The handler should take over from here!");
}
4

4 Answers

13
votes

This tip on the Spring forum may help you.

Likely you have configured the beans for your DispatchServlet in a webmvc-servlet.xml file (the *-servlet.xml file may be named differently)

If the XML file already includes another ExceptionResolver (like SimpleMappingExceptionResovler Spring wont automatically add any other resolvers for you. So manually adding the annotation resolver like so:

<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver" />

Should enable the @HandlerException processing.

13
votes

Frustratingly, I have suffered from this as well. I discovered that if you mistakenly implement Throwable instead of Exception the Exception resolver will just rethrow your Throwable as a IllegalStateException. This will fail to invoke your @ExceptionHandler.

If you've implemented Throwable instead of Exception try changing it to Exception instead.

Here's the code in question from InvocableHandlerMethod

catch (InvocationTargetException e) {
            // Unwrap for HandlerExceptionResolvers ...
            Throwable targetException = e.getTargetException();
            if (targetException instanceof RuntimeException) {
                throw (RuntimeException) targetException;
            }
            else if (targetException instanceof Error) {
                throw (Error) targetException;
            }
            else if (targetException instanceof Exception) {
                throw (Exception) targetException;
            }
            else {
                String msg = getInvocationErrorMessage("Failed to invoke controller method", args);
                throw new IllegalStateException(msg, targetException);
            }
        }
4
votes

I have found that @ExceptionHandler works with Throwable when you define method in such a manner:

@ExceptionHandler(Throwable.class)
@ResponseBody
public String handleException(Throwable e) {

}

In this case method has only one argument of type Throwable. If I try to use in this method some additional parameters (I tried to use Model), I receive 500 exception (this method isn't call). However this still works when additional parameters are HttpServlerRequest or HttpServlerResponse.

0
votes

It will not work, because when you return String you return View name.

Now your Spring MVC controller is searching for This method is never called! Why not?! view and can find.

Make sure that @ExceptionHandler is mapped to existing view.