My servlet request thread invokes a worker thread that can throw exceptions of many possible types. The worker thread catches any exception and passes it back to the request thread. I'd like to get that exception to the correct handler method in my Spring controller.
You cannot rethrow an exception from one thread in another thread, so the request thread wraps the original exception and throws that. That wrapper exception is currently being handled by a catch-all controller method annotated with #ExceptionHandler(Throwable.class). Because this handler exists, Spring does not look at the nested exception, so the nested exception is ignored.
I can add a handler for the wrapper exception type. In that, I'd like to unwrap the nested exception and ask Spring to route it to the correct handler. I've learned that Spring handles exceptions via a chain of resolvers that implement HandlerExceptionResolver. Is there a way I can invoke that chain directly from my handler?
Inject List<HandlerExceptionResolver> handlerExceptionResolvers into your controller, then go through the list and try to handle the exception. If it returns a non-null ModelAndView, this means the request has been handled:
Exception e = ...;
if(e != null)
for (HandlerExceptionResolver resolver : handlerExceptionResolvers)
if (resolver.resolveException(req, resp, null, e) != null)
return null;
Related
I have a global exception handler to share across REST #Controllers. For this I use a #ControllerAdvice with some #ExceptionHandler methods. This works fine. Now, if I add an #ExceptionHandler in a particular Rest Controller then that new handler takes precedence over the global exception handler and the global one is just never called.
What I need is actually to have both called. The order doesn't matter. The point is that there is some global, controller-agnostic error handling code and also some controller-specific error handling and I need both to execute. Is this possible? e.g. Can I somehow in the controller-specific handler (which is called first) mark the exception handling as not handled so the next handler in line is invoked?
I know I could inject the #ControllerAdvice in the #Controller and invoke the global handler from the specific one myself, but I rather keep the controller decoupled from the global exception handler
I don't think you can do this with out-of-the-box Spring. If you look under the hood at this method ExceptionHandlerExceptionResolver#doResolveHandlerMethodException, you can see that at first Spring looking for single method that will handle occurred exception:
...
ServletInvocableHandlerMethod exceptionHandlerMethod = getExceptionHandlerMethod(handlerMethod, exception);
if (exceptionHandlerMethod == null) {
return null;
}
...
You can also look at the implementation of getExceptionHandlerMethod method. First its trying to find appropriate handler within you controller methods, if nothing found - then within controller advisors.
After that it invokes it:
try {
if (logger.isDebugEnabled()) {
logger.debug("Invoking #ExceptionHandler method: " + exceptionHandlerMethod);
}
exceptionHandlerMethod.invokeAndHandle(webRequest, mavContainer, exception, handlerMethod);
}
catch (Exception invocationEx) {
if (logger.isErrorEnabled()) {
logger.error("Failed to invoke #ExceptionHandler method: " + exceptionHandlerMethod, invocationEx);
}
return null;
}
You should also note that Spring swallows any exception that might occur during original exception handling, so you can't even throw new exception from your first handler or rethrow original exception so it can be catched somewhere else (You can actually, but this is pointless).
So, if you really want to do this - I guess the only way is to write you own ExceptionHandlerExceptionResolver (maybe extend Springs ExceptionHandlerExceptionResolver) and modify doResolveHandlerMethodException method, so it looks for multiply exceptionHandlerMethod (one within controllers and one within advisors) and invokes it in a chain. This might be tricky :)
Also, you can look at this Jira ticket.
Hope it helps.
I wrote an #ExceptionHandler to send the exception in JSON for REST requests. However, due to the way Spring Security works, AccessDeniedExceptions must not be handled.
If I simply rethrow an AccessDeniedException in the handler, I get an ERROR level logging saying:
Failed to invoke #ExceptionHandler method: SomeMethod() throws java.lang.Exception
org.springframework.security.access.AccessDeniedException: Access is denied
...Stack...
I cannot safely disable ERROR level logging for the class logging it (ExceptionHandlerExceptionResolver), but having these stacktrace is quite confusing for operations people.
Is there anyway to make #ExceptionHandler not handle this specific exception?
I think you could just use global exception handler instead, so you don't manually handle this AccessDeniedExceptions,
this global exception will be thrown for every kinds of exceptions (except for the exception handlers that you handle manually):
#ControllerAdvice
public class GlobalHandler {
#ExceptionHandler(Exception.class)
public ModelAndView handleException() {
return new ModelAndView("errorGlobal");
}
}
I am getting the following error:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.NullPointerException
And to handle this in a controller, I have used the following code:
#ExceptionHandler(NestedServletException.class)
public ModelAndView handleServletErrors(){
System.out.println("Servlet Exception is thrown");
ModelAndView mv = new ModelAndView("error");
mv.addObject("error", "Error encountered while processing reqeust.");
return mv;
}
But this does not handle the exception thrown above. Whereas if I use NullPointerException class instead of NestedServletException, it works. Since Spring is throwing exception in response to NullPointerException shouldn't it be handled by the code above?
Quoting the documentation of #ExceptionHandler:
Annotation for handling exceptions in specific handler classes and/or handler methods.
This annotation will allow a method to handle exceptions that are thrown by handler methods, i.e. methods that are annotated with #RequestMapping. Quoting the Spring reference:
You can do that with #ExceptionHandler methods. When declared within a controller such methods apply to exceptions raised by #RequestMapping methods of that contoroller (or any of its sub-classes). You can also declare an #ExceptionHandler method within an #ControllerAdvice class in which case it handles exceptions from #RequestMapping methods from many controllers.
Since the exception thrown by your handler is NullPointerException, the exception handler method will handle that specific exception. It will not handle the generic NestedServletException that Spring uses to encapsulate servlet exceptions.
I have a situation where I support a framework that needs to resolve a specific exception, but only if that exception has a specific message code (internal exception). I have added a custom HandlerExceptionResolver to handle this specific exception but am curious how to "defer" the handling of this exception to later resolvers when I don't find a matching message code.
The API calls for returning ModelAndView and the documentation infers to return null for default processing. Is there anything I can return to indicate to invoke other resolvers? I could theoretically implement the BeanPostProcessor and capture any other resolvers, but that seems hacky...
Thanks in advance.
Returning null is the right thing to do.
If you look at DispatcherServlet, you'll see that it does the following when it comes to handling an Exception from your Controllers:
// Check registered HandlerExceptionResolvers...
ModelAndView exMv = null;
for (HandlerExceptionResolver handlerExceptionResolver : this.handlerExceptionResolvers) {
exMv = handlerExceptionResolver.resolveException(request, response, handler, ex);
if (exMv != null) {
break;
}
}
Essentially this means that it will try all registered HandlerExceptionResolver instances within the ApplicationContext until it finds one that can handle the Exception. By returning null, you are simply saying that DispatcherServlet should try the next one in the chain.
I assume that it makes sense for your HandlerExceptionResolver to be called before the other default ones added by Spring. If that is the case, see my other post on how to order your HandlerExceptionResolver instances here.
I have heard that it is possible to log (or do something else) Exceptions with Spring in my web-App, so I don't have to manually insert in every "catch(){}" block the Log-function.
Does anyone have experience with Spring-overall-logging? I just want to get informed when an error appears
ExceptionHandler is the central point for handling unexpected Exceptions that are thrown during the Faces lifecycle. The ExceptionHandler must not be notified of any Exceptions that occur during application startup or shutdown.
See the specification prose document for the requirements for the default implementation. Exceptions may be passed to the ExceptionHandler in one of two ways:
1.)By ensuring that Exceptions are not caught, or are caught and re-thrown.
This approach allows the ExceptionHandler facility specified in section JSF.6.2 to operate on the Exception.
2.)By using the system event facility to publish an ExceptionQueuedEvent that wraps the Exception.
This approach requires manually publishing the ExceptionQueuedEvent, but allows more information about the Exception to be stored in the event. The following code is an example of how to do this.
Global Exception Handler – Exception Handling is a cross-cutting concern, it should be done for all the pointcuts in our application. We have already looked into Spring AOP and that’s why Spring provides #ControllerAdvice annotation that we can use with any class to define our global exception handler.
The handler methods in Global Controller Advice is same as Controller based exception handler methods and used when controller class is not able to handle the exception.
Sample Code
#ExceptionHandler(Exception.class)
public ModelAndView getExceptionPage(Exception e, HttpServletRequest request) {
request.setAttribute("errorMessageObject", e.toString());
return model;
}
** Here we can catch the base exception class Exception.class or any other exception class. Also we can throw and catch our own custom defines exception class.