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

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

Related

HandlerInterceptor has an Object hander parameter, what types will get passed into the interceptor?

The HandlerInterceptor interface has a parameter Object handler, which means implementing code has to do type checking on the handler object in order to use it, and cast it as appropriate.
Code snippets I've found seem to assume the handler is always a HandlerMethod object and return true if this isn't the case, but I want to understand why this seems to be a common implementation to make a robust implementation.
A standard way of implementing this interface seems to be:
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyInterceptor implements HandlerInterceptor {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
if (handler instanceof HandlerMethod) {
// ...
return x; // whether or not to proceed with execution
}
return true; // fallback value in case handler wasn't a HandlerMethod
}
}
The Spring javadoc seems to ignore the fact that the interface has an Object type in it, it's very unhelpful for my understanding of this interface.
Some questions that might aid my understanding of how this interface is supposed to be implemented:
Why is true a sensible default if we get a handler that's not the object we expect it to be?
Which types can an HandlerInterceptor take for its handler parameter?
Under what circumstances could handler be a different type, if any?
Why is it an Object, not a HandlerMethod, parameter?
Basically the handler argument can be any type for which a HandlerAdapter exists. Most commonly used will be the RequestMappingHandlerAdapter utilizing a HandlerMethod.
But it could be a regular class, a servlet, or even a function (when using the functional approach). Spring Web Services also has an implementation as well as Spring Integration.
Spring itself will support the following out-of-the-box
HandlerMethod
HandlerFunction
Controller
Servlet
HttpRequestHandler
WsdlDefinition (Spring Web Services)
XsdDefinition (Spring Web Services)
So no it isn't always a HandlerMethod but it will be for most users.
Here's what javadoc of HandlerInterceptor#preHandle() says:
Interception point before the execution of a handler. Called after HandlerMapping determined an appropriate handler object, but before HandlerAdapter invokes the handler.
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 decide to abort the execution chain, typically sending an HTTP error or writing a custom response.
This means interceptors are not supposed to touch the handler at all so they don't need to know anything about it. Their only job is to decide whether to pass the request further or not.
BTW, none of the standard HandlerInterceptor#preHandle() implementations in org.springframework.web.servlet.* try to analyze the true handler parameter type and do any logic based on it.
Why is it an Object, not a HandlerMethod, parameter?
From the org.springframework.web.servlet.HandlerMapping#getHandler() javadoc:
Return a handler and any interceptors for this request. The choice may be made on request URL, session state, or any factor the implementing class chooses.
The returned HandlerExecutionChain contains a handler Object, rather than even a tag interface, so that handlers are not constrained in any way. For example, a HandlerAdapter could be written to allow another framework's handler objects to be used.

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.

How to setThreadContextInheritable(true) via xml on Spring's dispatcherportlet and dispatcherservlet

I want to make the current request available to child threads without passing on the original request as method parameters through several layers. The application runs both as a servlet and as a portlet.
Normally, DispatcherServlet and DispatcherPortlet set the current request into a RequestContextHolder on the current thread. That way, a call thread has access to the current request. The request is not propagated to child threads.
In my case, the request spawns a subthread where it makes a ReST call using RestTemplate, and I need to access the original request in an ClientHttpRequestInterceptor that intercepts the RestTemplate. The request that is passed to intercept is useless, I need the original request that hit the server.
Both DispatcherServlet and DispatcherPortlet have a feature to pass on the RequestContext to child threads: setThreadContextInheritable(true). However, it seems not so easy to set that flag to true. There is no init-param which sets it, and usually you specify them in web.xml or portlet.xml.
Is there a way to customize a dispatcher portlet or servlet via their setters using xml configuration? The only way I found is to write a custom dispatcherservlet/portlet which sets the flag to true internally and use that in web.xml and portlet.xml.
There is no way to do this directly through XML configuration. You would need to do as you said and create a subclass of DispatcherServlet which internally calls setThreadContextInheritable(true).
The alternative is to perform your ServletContext configuration in Java. Spring provides a WebApplicationInitializer and a number of useful subtypes where you can register a customized DispatcherServlet (other servlets and filters).
You'd create your instance.
DispatcherServlet servlet = new DispatcherServlet(context);
servlet.setThreadContextInheritable(true);
and then register it
ServletRegistration.Dynamic dispatcher = servletContext.addServlet("dispatcher", servlet);

#ControllerAdvice methods seem to bypass interceptors

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.

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