@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
I had the same problem when I missed this imprort
:
import org.springframework.http.HttpStatus;
Eclipse didn't offer me to add it in Quick Fix, I added the row manually and it helped.
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");
}
}
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.
上一篇: 如何在PHP中使用BLENC?