#ControllerAdvice methods seem to bypass interceptors - java

I have a class annotated with #ControllerAdvice with some central exception handling for my api. One of the exceptions it handles is the MethodArgumentNotValidException which gets thrown when a request method parameter annotated with #Valid, fails validation.
In my application, I also have a CORS interceptor setup which adds the "Access-Control-Allow-Origin" header to the servlet response when the request is successful. However, it seems that when validation fails on the parameter annotated with #Valid, my interceptor gets bypassed. My exception handler needs to send back error information for form fields that are invalid so they can be dealt with in the browser.
Just wondering if this is normal behaviour that my interceptor gets bypassed when an exception is thrown, or if I'm missing some configuration in the #ControllerAdvice class.

This is indeed normal behavior.
From the javadoc of HandlerInterceptor.postHandle
Intercept the execution of a handler. Called after HandlerAdapter actually invoked the handler, but before the DispatcherServlet renders the view. Can expose additional model objects to the view via the given ModelAndView.
DispatcherServlet processes a handler in an execution chain, consisting of any number of interceptors, with the handler itself at the end. With this method, each interceptor can post-process an execution, getting applied in inverse order of the execution chain.
Arguably the MethodArgumentNotValidException is thrown before the method is actually called, it is called in preparing the actual method call. Actually the postHandle is only executed after successful execution/invocation of the method. In case of an exception only the preHandle and afterCompletion methods are called.

Related

Why doesn't DispatcherServlet invoke my HandlerInterceptor?

I know that in JavaEE, filters can intercept any request to a servlet. But Interceptors in Spring MVC are not exactly the same. If you look at the diagram below, you will see that Interceptors come after Dispatcher Servlet.
Let me give you an example before I ask my question.
I have a controller, which has 2 methods in it that are mapped to two different requests. One accepts GET requests and other accepts POST requests. Now if I add an interceptor in my web application, that interceptor will sit before Controller. Meaning that before controller method is hit, first a request will hit my interceptor's preHandle method.
Now say that in my app, two controllers methods look like this:
#Controller
public class myController{
#RequestMapping(value = "/test", method = RequestMethod.GET)
public String test1(){
return "abc";
}
#RequestMapping(value = "/login", method = RequestMethod.POST)
public String test1(){
return "xyz";
}
And lets say I have a simple interceptor like this:
public class URLInterceptors extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("REQUESTED SERVLET PATH IS: " + request.getServletPath());
return true;
}
}
Now, if I make a GET request to /test, my interceptor is hit and it prints the servlet path, but when I make a GET request to /login, I know it will fail because my method that handles /login mapping accepts only POST requests, however before it throws '405 Request method 'GET' not supported' error, it should at least hit first my interceptor? It doesn't. I I don't want to change POST to GET. So the question is why?
Part of this is explained in
Why does Spring MVC respond with a 404 and report "No mapping found for HTTP request with URI [...] in DispatcherServlet"?
In summary, the DispatcherServlet attempts to find an appropriate handler for your request by using a HandlerMapping (see your graphic). These handlers are actually adapters that wrap the actual handler method (a #RequestMapping annotated method in this case) with the interceptors you've registered. If this handler is found, then the DispatcherServlet can proceed, invoke interceptors, and, if required, invoke your handler method.
In your case, because your #RequestMapping is restricted to POST requests and your request is a GET, the DispatcherServlet fails to find an appropriate handler and therefore returns an error before it's had a chance to invoke any interceptors.
Note that the javadoc states
A HandlerInterceptor gets called before the appropriate HandlerAdapter
triggers the execution of the handler itself.
but your DispatcherServlet never found a handler to begin with.
You might want to consider using a Servlet Filter instead.

Difference between HandlerInterceptor and WebRequestInterceptor?

While writing interceptor for my application I noticed HandlerInterceptor and WebRequestInterceptor here.
I noticed that HandlerInterceptor's method take HttpServletRequest, HttpServletResponse, Object(handler) and other params
while WebRequestInterceptor take WebRequest (a wrapper of HttpServletRequest).
But I don't know what is the difference between these two interceptors.
Although seeing Spring API I can guess that WebRequestInterceptor can not commit response while HandlerInterceptor can do that. Please correct me here if I am wrong.
With a HandlerInterceptor you can:
Change the HttpServletResponse in preHandle method
Apply filters based on handler object. For example, you can apply some filters based on presence of some annotations on HandlerMethod
Prohibit the execution of the handler by returning false in preHandle method.
HandlerInterceptor can be used for a large field of preprocessing aspects, e.g. for authorization checks, or common handler behavior like locale, theme changes or adding Cache-Control headers. Its main purpose is to allow for factoring out repetitive handler code.
One of the canonical use cases of WebRequestInterceptor is preparing context resources (such as a Hibernate Session) and expose them as request attributes or as thread-local objects. Also, you can modify those context resources after successful handler execution (for example, flushing a Hibernate Session). For example, OpenEntityManagerInViewInterceptor binds a JPA EntityManager to the thread for the entire processing of the request.
Although seeing Spring API I can guess that WebRequestInterceptor can
not commit response while HandlerInterceptor can do that. Please
correct me here if I am wrong.
WebRequestInterceptor interface is deliberately minimalistic to keep the dependencies of generic request interceptors as minimal as feasible. If you need to change the response, you should use HandlerIntercepter or Filters.

what's difference between Controller and Handler in Spring MVC?

The documentation of Spring MVC sometimes says about "handlers" or "request handlers". For instance, http://docs.spring.io/autorepo/docs/spring/4.0.4.RELEASE/javadoc-api/org/springframework/web/servlet/handler/SimpleUrlHandlerMapping.html says:
Implementation of the HandlerMapping interface to map from URLs to request handler beans
And sometimes it says about controllers. For instance, there is an interface called org.springframework.web.servlet.mvc.Controller ( http://docs.spring.io/spring-framework/docs/2.5.x/api/org/springframework/web/servlet/mvc/Controller.html ).
My question is: are Controllers and Handlers the same?
Generally speaking, a Controller is Handler, but a Handler doesn't have to be a Controller.
For example, HttpRequestHandler, WebRequestHandler, MessageHandler are all handlers which can work with the DispatcherServlet. ( (#)Controller is a handler for executing a web request and returning a view.)
Shortly, Handler is just a term, it is neither a class nor interface. And it is responsible for executing the Mapping.
A Controller is a specific type of Handler but not all Handlers are Controllers.
To execute a type of Handler there is a HandlerAdapter and for each type of Handler there is a different HandlerAdapter. You have Controller and #Controller, HttpRequestHandler and also a plain Servlet can be a Handler. Or if you have some custom things you can even implement your own.
Handler is a inclusive i.e. covering all the services details.
Controller is an an exclusive implementation.
In Spring we have the following different types of handlers:
HandlerMapping: The HandlerMapping strategy is used to map the HTTP client request to some handler controller(or controllers) and/or method. This is done based on the request URL and the HTTP method, but may also include the request parameters, request headers, or other custom factors.
For example: DefaultAnnotationHandlerMapping, SimpleUrlHandlerMapping, BeanNameUrlHandlerMapping.
HandlerAdapter: The DispatcherServlet uses a HandlerAdapter to invoke a method. Which is decouples the DispatcherServlet from controller implementations classes.
For example: AnnotationMethodHandlerAdapter, HttpRequestHandlerAdapter, RequestMappingHandlerAdapter, SimpleControllerHandlerAdapter, SimpleServletHandlerAdapter

RestEasy Post Process Interceptor chain not traversed when response created by ExceptionMapper

I am using RestEasy to build up my Restful web services. I have implemented ExceptionMappers to prepare specific exception responses.
I have also implemented MessageBodyWriterInterceptors and a couple of PostProcessorInterceptors.
Issue: All works fine when any resource does not throw any exception. My implementation works as expected. All the post processor interceptors and the message body writer interceptors are called.
But when an exception is thrown from any of the resource methods, the registered ExceptionMappers are called and it is creating the response. But in this case the post processor interceptor chain is not traversed. They are not getting called.
What should I do in this case. Write that interceptor logic in my exception mapper or is there is solution available?
Post processors do not get called if an exception is thrown. They are on different, parallel resolution paths:
/ 'Normal' JAX-RS response -> Post Processors -> Message Body Writers
Processing
\ Exception -> Exception Mappers
If you have logic that needs to be run in both your post processors and exception mappers then you will need to incorporate it in both (preferably through a common, utility class).

Capture Spring MVC DispatcherServlet exceptions with ExceptionResolver

I am trying to return a valid JSON body for every request of an Spring MVC service, both correct and invalid.
Using #ExceptionHandler and a combination of ExceptionHandlerExceptionResolver, DefaultHandlerExceptionResolver and my own AbstractHandlerExceptionResolver I am able to process and set a body for almost all invalid requests that are dispatched to a valid controller or rejected by Spring Security.
However, errors thrown by the DispatcherServlet like noHandlerFound, can't be intercepted, so the response has a valid HTTP status code like 404, but the body contains the Tomcat default XML error.
Anybody knows how to set up or configure an Spring Exception Resolver so all failed requests are intercepted and a valid JSON body could be set?
There is a section explaining how is spring handling exception resolver for dispatcher servlet:
The dispatcher's exception resolution strategy can be specified via a
HandlerExceptionResolver, for example mapping certain exceptions to
error pages. Default are AnnotationMethodHandlerExceptionResolver,
ResponseStatusExceptionResolver, and DefaultHandlerExceptionResolver.
These HandlerExceptionResolvers can be overridden through the
application context. HandlerExceptionResolver can be given any bean
name (they are tested by type).
to be able to support Dispatcher exception handling overriding you have to implement HandlerExceptionResolver and Ordered class and declare the implementation as spring bean. You must return getOrder value as Integer.MIN_VALUE to override any other existing handler.

Categories