Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

@ControllerAdvice exception handling together with @ResponseStatus

I have @ControllerAdvice class, which handles a set of exceptions. Than we have some other exceptions, which are annotated with @ResponseStatus annotation. To combine both approaches, we use technique described in blog post: http://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc, namely in the ControllerAdvice we handle generic Exception in the following way:

    @ExceptionHandler(value = Exception.class)
    public ModelAndView defaultErrorHandler(HttpServletRequest req, Exception e) throws Exception {
        // If the exception is annotated with @ResponseStatus rethrow it and let
        // the framework handle it - like the OrderNotFoundException example
        // at the start of this post.
        // AnnotationUtils is a Spring Framework utility class.
        if (AnnotationUtils.findAnnotation(e.getClass(), ResponseStatus.class) != null)
            throw e;

        // Otherwise setup and send the user to a default error-view.
        ModelAndView mav = new ModelAndView();
        mav.addObject("exception", e);
        mav.addObject("url", req.getRequestURL());
        mav.setViewName(DEFAULT_ERROR_VIEW);
        return mav;
    }

It works like a charm, however, using this technique causes error with the following text to appear in the application log:

2014-06-11 15:51:32.907 ERROR o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver - Failed to invoke @ExceptionHandler method: ...

This is caused by this piece of code in ExceptionHandlerExceptionResolver:

try {
            if (logger.isDebugEnabled()) {
                logger.debug("Invoking @ExceptionHandler method: " + exceptionHandlerMethod);
            }
            exceptionHandlerMethod.invokeAndHandle(webRequest, mavContainer, exception);
        }
        catch (Exception invocationEx) {
            logger.error("Failed to invoke @ExceptionHandler method: " + exceptionHandlerMethod, invocationEx);
            return null;
        }

Does anybody know how to combine these two approaches to exception handling properly to avoid the error in the log?

Thanks, Jan

like image 681
Jan Stastny Avatar asked Jun 11 '14 13:06

Jan Stastny


2 Answers

This is an old question, but I just encountered this today and found a better solution than disabling logging for ExceptionHandlerExceptionResolver. Turns out that the issue can be resolved by upgrading to the latest version of the spring framework (4.3.8 worked for me). The ExceptionHandlerExceptionResolver has been fixed to detect if the original exception was rethrown from an @ExceptionHandler. In this case, the exception is no longer logged.

like image 71
Noky Avatar answered Nov 13 '22 18:11

Noky


I dealt with it in a slightly different way which I think solves your problem.

Since I know that basically I want to deal with 404's differently to 500s of whatever hue, I look for a NOT_FOUND status and send that accordingly, which seems to work and then you're not re-throwing the exception.

This means

@ControllerAdvice
public class MVCExceptionHandler {
    private static final Logger log = LogManager.getLogger();

    @ExceptionHandler(Exception.class)
    public ModelAndView defaultErrorHandler(HttpServletRequest req, HttpServletResponse res, Exception ex) throws Exception {

        // If the exception is annotated with @ResponseStatus check if it's a 404 in which case deal with it, otherwise 500 it.
        if (AnnotationUtils.findAnnotation(ex.getClass(), ResponseStatus.class) != null) {
            ResponseStatus rs = AnnotationUtils.findAnnotation(ex.getClass(), ResponseStatus.class);
            if (HttpStatus.NOT_FOUND.equals(rs.value())) {
                res.setStatus(HttpStatus.NOT_FOUND.value());
                return new ModelAndView("error/404");
            }
        }

        log.error("Error while loading", ex);

        return new ModelAndView("error/500");

    }
}
like image 28
Pete Storey Avatar answered Nov 13 '22 20:11

Pete Storey