Nested Exception handling in Spring MVC - java

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.

Related

Can I directly invoke the Spring exception resolvers?

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;

Custom #ControllerAdvice in Spring for exception handling

I am trying to map exceptions from my rest controllers to responses which have a body, and to do it in a central place.
I have tried this:
#Order(Ordered.HIGHEST_PRECEDENCE)
#ControllerAdvice
public class RestErrorResponseExceptionHandler extends ResponseEntityExceptionHandler {
#Override
protected ResponseEntity<Object> handleExceptionInternal(
Exception ex, Object body, HttpHeaders headers, HttpStatus status, WebRequest request) {
super.handleExceptionInternal(ex, body, headers, status, request);
return ResponseEntity.status(status).body(Error.from(status));
}
}
The problem is that the handler is never triggered.
If I define a custom method with #ExceptionHandler in my rest controllers, or extend something that has #ExceptionHandler, then all works well, but that introduces some bad design.
It is my understanding that Spring will first try to look in controller for exception handling methods, then it will check for registered handlers.
I am trying to verify the behaviour via WebMvcTest, and responses I'm getting are not the Error objects that I'm expecting.
Is there something I'm missing?
The ControllerAdvice is a configuration that have to be registered by Spring. You have to move your class in the config package or you can register it by annotation.
In my case, I work with a controllerAdvice like this one :
#ControllerAdvice
public class GlobalControllerExceptionHandler {
#ExceptionHandler(MyException.class)
public ResponseEntity<String> reponseMyException(Exception e) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).body("my message");
}
}
Spring Framework provides following ways to help us achieving robust exception handling.
Controller Based – We can define exception handler methods in our controller classes. All we need is to annotate these methods with #ExceptionHandler annotation. This annotation takes Exception class as argument. So if we have defined one of these for Exception class, then all the exceptions thrown by our request handler method will have handled.
These exception handler methods are just like other request handler methods and we can build error response and respond with different error page. We can also send JSON error response, that we will look later on in our example.
If there are multiple exception handler methods defined, then handler method that is closest to the Exception class is used. For example, if we have two handler methods defined for IOException and Exception and our request handler method throws IOException, then handler method for IOException will get executed.
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.
HandlerExceptionResolver – For generic exceptions, most of the times we serve static pages. Spring Framework provides HandlerExceptionResolver interface that we can implement to create global exception handler. The reason behind this additional way to define global exception handler is that Spring framework also provides default implementation classes that we can define in our spring bean configuration file to get spring framework exception handling benefits.
SimpleMappingExceptionResolver is the default implementation class, it allows us to configure exceptionMappings where we can specify which resource to use for a particular exception. We can also override it to create our own global handler with our application specific changes, such as logging of exception messages.
Make sure of 2 things and your code will work.
Your #ControllerAdvice class is available in component-scan path.
Make sure the methods in your #ControllerAdvice have structure somewhat like this-
#ExceptionHandler(value = { RequestProcessingException.class })
public #ResponseBody ResponseEntity<ErrorMessageBO> hotelConfigServiceExceptionHandler(HttpServletRequest request, RequestProcessingException e) {
logger.error("Exception with tracking Id: {}, dev message: {} and Message:", RequestContextKeeper.getContext().getRequestId(), e.getDeveloperMessage(),e);
return new ResponseEntity<ErrorMessageBO>(new ErrorMessageBO(e.getErrorCode(), e.getMessage(),RequestContextKeeper.getContext().getRequestId(),e.getDeveloperMessage()), HttpStatus.OK);
}

Make #ExceptionHandler handle every exception except AccessDeniedException?

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");
}
}

Why is java ws rs ExceptionMapper is picking non application exceptions also?

I have a web application in which I throw some custom exceptions(application exceptions annotated with #ApplicationException) and there is an exception mapper(provider annotated with #Provider) for each. Recently I forgot to annotate an exception with #ApplicationException and still the mapper is able to identify the exception and format the response properly.
Then I checked the documentation and I understood that the annotation will be inherited by its child class by default. So I removed the annotation from the super class and checked. The mapper still identified the exception and formatted the response.
Then I went even forward and tried throwing java.lang.IllegalArgumentException and wrote a mapper class for it. It also worked properly. Is javax.ws.rs.ext.ExceptionMapper independent of the exception being thrown. Will it not check if whether thrown exception is really annotated with #ApplicationException?
#Provider
public class IllegalArgumentExceptionMapper implements ExceptionMapper<java.lang.IllegalArgumentException> {
#Override
public Response toResponse(java.lang.IllegalArgumentException exception) {
return Response.status(Status.BAD_REQUEST).entity(exception.getMessage()).build();
}
}
Somewhere in my service class:
throw new java.lang.IllegalArgumentException("Problem with the payload. Please check the payload you are sending");
The answer is no, it will not check if whether thrown exception is really annotated with #ApplicationException.
The exception mapper is independent of the #ApplicationException.
All the exception mapper knows is, if there's no exception caught until the almost last layer, it will be processed here, if it find a matching provider.
You can also actually create a provider for RuntimeException and all exception happened in the REST request will land here (but this is not good practice, we should always throw custom exception and catch them with the provider and convert them to good error response).
When you annotate the exception with #ApplicationException you can control things like whether the transaction should be rollback, and whether it will be wrapped by EJBException etc etc.

Exception Logging with Spring

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.

Categories