How does spring inject arguments into the controller method - java

public ModelAndView loginPage(HttpServletRequest request, Locale locale) {}
As you know, Spring injects HttpServletRequest and Locale into the method. I want to know
how is it done behind the curtains ? My guess is, there is a data converter system working behind
that takes http request headers and body data and fill them into the suitable classes that are given
in arguments by the coder. Am I right ?

When working with Spring MVC there are multiple parts moving to solve the problem of mapping HandlerMapping and execution HandlerAdapter.
Each #Controller is scanned for #RequestMapping annotated methods, the methods are mapped to URLs based on the metadata available in the #RequestMapping annotation, this is done by the RequestMappingHandlerMapping class.
When a request comes in the specific method is matched on the incoming request. This selected method is passed the RequestMappingHandlerAdapter which consults all method arguments. The actual handling of the method argument is left to different HandlerMethodArgumentResolver implementations (you could also implement your own).
The same happens for the return value of your method although that is delegated to a HandlerMethodReturnValueHandler.

Yes, you're right. In short, there is a single entry point into the application (there may be more than one entry point) that routes incoming traffic, passing incoming data to methods as parameters. This is known as the front controller pattern.
Spring's DispatcherServlet is an implementation of the front controller pattern. The Spring reference details the pattern as followed in Spring, and the pattern is listed among the core Java EE patterns.

Related

Is there a way to use Google's Custom Methods with Jersey Resources?

I was looking for a way to make my JAX-RS APIs more readable and came across with Google's Custom Methods approach:
https://cloud.google.com/apis/design/custom_methods
I was looking for this because some of my entities perform more actions than I could express with traditional HTTP verbs. Google pattern is to use a colon (:) at the end of the URI, separating the entity/collection from the desired action.
I tried to apply this pattern to a simple Jersey resource, just to test how it could be done. I've got a resource class StudentDetailsResource annotated with #Path("students/{studentId}") and a few methods also annotated with #Path.
If my method has another entity before the custom method, then all is ok. Let's say the enrol method is annotated with
#Path("subjects/{subjectId}:enroll").
The problem rises when the action is right after the Resource Class URI, because #Path uses a URI Template that prefixWithSlash all sub-resources. So if I have a dropout method, the annotation would look like #Path(":dropout"), but the URI template would become /students/{studentId}/:dropout, an this /: would break in the matching phase.
I have read about Jersey Providers and ResourceDelegates, but I couldn't find a way to replace the URI Template default action of prefixWithSlash.
The question is: how can I apply Google's custom method approach or how can I avoid the default prefixWithSlash behaviour with Jersey?
Note: I know this is a silly example and there are other ways to solve this specific case, but I have more complex cases which can benefit from the custom methods.

Model population in Spring MVC #ExceptionHandler

Is there a way to let my #ExceptionHandler methods have access to the model attributes populated by the #RequestMapping method that triggered the exception in question?
Or, more specifically for my problem: my models passed to my views have some data populated from #ModelAttribute (such as detailed information on the user account) methods, and I'd like those to be also set in my #ExceptionHandler methods.
For instance, since my error view page uses the same header and menu as my other pages, I want to show the current user name (and other info, such as number of unread messages etc).
I know the #ExceptionHandler exists outside the #Transaction (as it should!), so I obviously can't just (and don't want to) run some queries again. Rather, I'd like to pre-populate the ModelMap or ModelAndView or whatever, and make sure the exception handler gets hold of that - or at least that the model data is made available when rendering the view.
I hope this question makes sense, I'm fairly new to Spring MVC so I may be mixing a few concepts here and there...
The javadoc of ExceptionHandler states the following with regard to the arguments that can be passed to the handler method:
Handler methods which are annotated with this annotation are allowed
to have very flexible signatures. They may have arguments of the
following types, in arbitrary order:
1. An exception argument: declared as a general Exception or as a more specific exception. This also serves as a mapping hint if the annotation itself does not narrow the exception types through its value().
2. Request and/or response objects (Servlet API or Portlet API). You may choose any specific request/response type, e.g. ServletRequest / HttpServletRequest or PortletRequest / ActionRequest / RenderRequest. Note that in the Portlet case, an explicitly declared action/render argument is also used for mapping specific request types onto a handler method (in case of no other information given that differentiates between action and render requests).
3. Session object (Servlet API or Portlet API): either HttpSession or PortletSession. An argument of this type will enforce the presence of a corresponding session. As a consequence, such an argument will never be null. Note that session access may not be thread-safe, in particular in a Servlet environment: Consider switching the "synchronizeOnSession" flag to "true" if multiple requests are allowed to access a session concurrently.
4. WebRequest or NativeWebRequest. Allows for generic request parameter access as well as request/session attribute access, without ties to the native Servlet/Portlet API.
5. Locale for the current request locale (determined by the most specific locale resolver available, i.e. the configured LocaleResolver in a Servlet environment and the portal locale in a Portlet environment).
6. InputStream / Reader for access to the request's content. This will be the raw InputStream/Reader as exposed by the Servlet/Portlet API.
7. OutputStream / Writer for generating the response's content. This will be the raw OutputStream/Writer as exposed by the Servlet/Portlet API.
8. Model as an alternative to returning a model map from the handler method. Note that the provided model is not pre-populated with regular model attributes and therefore always empty, as a convenience for preparing the model for an exception-specific view.
So in order to populate the model of the view you will be using to display the error, you'll probably have to go with WebRequest
Thought its possible, but:
http://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc
Important Note: the Model may not be a parameter of any
#ExceptionHandler method. Instead, setup a model inside the method
using a ModelAndView as shown by handleError() above.
Seems you have to cant pass ModelAndView as in any other controller, so it has to be built once again + fetch possible values from HttpServletRequest.

Creating Custom Annotation Using Spring that supports Flexible Method Signature

In Spring MVC, Inside a Controller class, the method annotated with #RequestMapping annotation are allowed to have Flexible Method Signature.
If I want to do something like this with my own custom annotation, Can somebody give me some pointers for the same.
Thanks in Advance.
Spring MVC has a lot of features in that regard so it might be easier to look elsewhere as a starting point. The new messaging abstraction that was introduced in Spring 4 has similar features.
Look at #MessageMapping which allows you to build a flexible signature against a Message instance. You could for instance inject a header of the message
public void foo(#Header("myHeader") int myHeader)
Or you could validate that the payload against a Validator
public void bar(#Payload #Validated Order order)
The core of the infrastructure is located in InvocableHandlerMethod which is going to invoke a java.lang.reflect.Method you have provided on a given bean instance based on an incoming Message and additional parameters you may provide (see public final Object invoke(Message<?> message, Object... providedArgs)
To create that instance, you need to provide a set of HandlerMethodArgumentResolver. Each HandlerMethodArgumentResolver is responsible to handle a method parameter. In short, that's basically going to provide you a MethodParameter instance (i.e. a reference to a parameter of the method you want to handle, such as the annotated order in the last example) and you're going to tell if you support it or not and when you do, handle that parameter so that the right value is injected. For the header example, the implementation looks for a header with the name on the annotation. Simple!
A set of default resolvers are created for example in SimpAnnotationMethodMessageHandler (look at initArgumentResolvers). That's going to show you the kind of parameters you can inject there by default. By extending that list (or providing custom instances) you can augment what the user can use in the method signature.
In Spring 4.1, we rely on this infrastructure to provide JMS listener annotated endpoints and those endpoints may have a flexible signature as well. It's actually already implemented so you may want to have a look to that for yet another example.

Struts2 + spring autowiring actions by-name without exposing certain properties

I am using Struts 2 and Spring autowiring. Right now, the default strategy is set to by-name, but usually we use the constructor and the fallback works to autowire in properties when only one implementing class is available.
There is one property however that I'd like to wire into an action class that has several implementing classes, so I made the Action a java bean, with the properties as fields that can be set. Unfortunately, the only ways that these will be used (apparently) is if they have a public getter/setter, which also exposes them to the type converter at request time. In other words, if a client adds their name to the request as form fields or parameters, Struts will attempt to write those values to them.
So my question is, is it actually possible to use by-name autowiring without exposing properties like that (which may or may not be a security hazard), or am I better off just using XML and defining the Action as an object with scope prototype?
I did eventually track down the documentation for the ParametersInterceptor which actually lists three ways you can limit what parameters are set by the interceptor.
Configuring excludeParams in the parameter configuration, which is a global regex which applies to all actions (not what I want, also possibly deprecated as it is no longer described in the most recent class docs).
Setting excludeMethods (does the same as the previous, the preferred method for global excludes)
Implementing ParameterNameAware, which is the closest to what I wanted. Here you can whitelist what parameters are used.
In the end, defining the action as a prototype object in the normal Spring configuration seemed to be the most prudent. Letting the action manage what parameters it has means another place where parameters need to be explicitly white listed every time a change is made.

Spring MVC isFormSubmission() equivalent for annotations?

With Spring MVC, it's easy to express a concept like "A user is submitting the form if they use POST or if they include the 'isSubmit' parameter." You'd just extend SimpleFormController and override the isFormSubmission method.
However, Spring MVC now uses these neat annotations like #RequestMapping to handle requests. #RequestMapping has an obvious filter for whether somebody used a GET or a POST, but I don't see any inherent support for all of the useful logic SimpleFormController provided. Is it still available to me with annotations?
So, after a bit of investigation, there are in fact a couple of ways to handle this situation.
The first way is to go ahead and use a SimpleFormController with with #RequestMapping annotation at the class level. A lesser-known but pretty cool property of #RequestMapping is that it knows perfectly well how to deal with the classes that implement Spring's Controller interface. The only downside here is that I'm still using the old MVC interfaces and classes, and they're going to be deprecated in Spring 3.0.
The second way was pointed out by kgiannakakis above. Simply create a #RequestMapping method for every way that the submit can be called, and have them all just call a single submit method, either in a constructor-chaining style or with some private method. Simple and easy to understand. Thanks, kgiannakakis!
Copying from here:
Path mappings can be narrowed through parameter conditions: a sequence of
"myParam=myValue" style expressions, with a request only mapped if each such
parameter is found to have the given value. "myParam" style expressions are
also supported, with such parameters having to be present in the request
(allowed to have any value). Finally, "!myParam" style expressions indicate
that the specified parameter is not supposed to be present in the request.
You can only use the RequestMapping options to define the desired functionality. The Annotations Controller doesn't implement any interface to work with.
Here is one example of using Path mappings:
#RequestMapping(params = "formAction=APPROVE", method = RequestMethod.POST)
public String myMethod ()....
This method will only be called then for POSTs where there is a field named "formAction" with a value of "APPROVE".
The other answers listed work fine for a method annotated with #RequestMapping.
However, if you want to achieve the same thing on a method annotated with #InitBinder, you can simply do this:
#InitBinder
public void initBinder(HttpServletRequest request) {
if ("POST".equals(request.getMethod()){
//Do something
}
}

Categories

Resources