Where is databinding mapping stored for a controller? - java

In the following controller
#Controller
public class MyFormController {
#InitBinder
public void initBinder(WebDataBinder binder) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
dateFormat.setLenient(false);
binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
}
// ...
}
The class does not inherit any other class or it doesn't have any WebDataBinder instance variable. How come then the custom editors are stored and where?

The Spring MVC infrastructure is complex. There are a lot of pieces that come together to invoke your #Controller handler method. I explain some of it in my answer here.
In summary, Spring MVC scans your #Controller classes for #RequestMapping annotated methods. It creates mappings for these in a RequestMappingHandlerMapping and uses a RequestMappingHandlerAdapter to dispatch to them, ie. invoke your handler methods.
Before it invokes the method, it goes through a couple of housekeeping steps. You can see these in the source code, here. The short version is:
It wraps the HttpServletRequest and HttpServletResponse in an adapter.
It creates factories producing Model and WebDataBinder instances (the latter come from your #InitBinder methods).
It creates a ServletInvocableHandlerMethod which encapsulates the invocation of your handler method with HandlerMethodArgumentResolver to generate arguments for your handler method and HandlerMethodReturnValueHandler to process the return value of your handler method.
It creates a ModelAndViewContainer which will potentially be used to later render a view as the HTTP response.
It prepares an async environment in case the request uses async components.
Then it invokes the method.
That WebDataBinder object you're curious about is stored and used in various places in the execution context described above.

Related

Spring `RestController` from `AbstractController` in TeamCity

The TeamCity plugin API allows adding controllers by extending their BaseController, which is a thin wrapper around Spring's AbstractController.
When I extend BaseController I can inject beans into the constructor in usual Spring manner. This is managed by a beans definition file like standard spring.,
To provide a Controller I must extend BaseController, override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response), and add the controller to the beans definition. I register a URL route as part of constructor initialisation.
That's about all the extension points available to me for Controller.
I was hoping to be able to write small framework that would allow me to annotate my classes with #RestController and #RequestMapping, etc.
What I think I need to do is:
Wire up an annotation processor to find my controllers and their methods.
Build some sort of mapper which maps #RequestMapping annotated methods to routes
Wire up some content handlers, eg serialising/unserialising for JSON and XML
Dispatch incoming requests to the appropriate method inside my handleRequest method
Most of the above has already been written in Spring and Jersey, and I am wondering where I start researching that.
What classes provide the above functionality?
I've tried a few things to try and instantiate MVC, but it seems to break when ApplicationContext is not available.
Not a TeamCity user. However I'll give my two cents, hoping for the best.
Being that you can register Spring Bean(s), why not trying out ClassPathBeanDefinitionScanner?
If you have access somehow to a Spring lifecycle hook, an initialization one, or if you are able to register a Configuration class, you can create a Bean of type BeanFactoryPostProcessor. I'll give you a Java example, but you should be able to translate it to XML pretty quickly.
#Bean
public BeanFactoryPostProcessor beanFactoryPostProcessor(final ApplicationContext applicationContext) {
return new BeanFactoryPostProcessor() {
#Override
public void postProcessBeanFactory(final ConfigurableListableBeanFactory beanFactory) throws BeansException {
if (beanFactory instanceof BeanDefinitionRegistry) {
try {
final BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
final ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(registry);
scanner.setResourceLoader(applicationContext);
scanner.scan("your.base.package");
} catch (final Exception e) {
// Handle
}
}
}
};
}
The ClassPathBeanDefinitionScanner will register all classes with Spring stereotype annotations.
You can also make a class implement the BeanFactoryPostProcessor interface directly.

Spring #initBinder method to be called only once inside a controller

I have a class that annotated with #RestController and #ControllerAdvice that has my requests mapped methods (#RequestMapping). Also in this class I added a method public void initBinder(WebDataBinder dataBinder) that is annotated with #InitBinder and responsible to register some custom editor.
Specifically, it is a propertyEditor that convert String to Enum.
I noticed that on every call to #RequestMapping method in my controller, my initBinder method is being called. Since in my opinion this editor registration should happen only once (initialization of controller), I want this to be set (called) only once.
Is there a way to do so?
Alternatively, you can use implementation of BindingInitializer for registering your custom Editor. You have to define a bean of class "org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" in your app context file and set its "webBindingInitializer" property with your implementation of BindingInitializer.
In any case, scope of WebDataBinder is for a request. Hope this helps.

Calling a #Bean annotated method in Spring java configuration

I'm curious about how spring injection handles calling methods with the #Bean annotation. If I put a #Bean annotation on a method, and return an instance, I understand that that tells spring to create a bean by calling the method and getting the returned instance. However, sometimes that bean has to be used to wire other beans or setup other code. The usual way this is done is to call the #Bean annotated method to get an instance. My question is, why doesn't this cause there to be multiple instances of the bean floating around?
For example, see the code below (taken from another question). The entryPoint() method is annotated with #Bean, so I would imagine spring will create a new instance of BasicAuthenticationEntryPoint as a bean. Then, we call entryPoint() again in the configure block, but it seems like entryPoint() returns the bean instance, and isn't called multiple times (I tried logging, and only got one log entry). Potentially we could call entryPoint() multiple times in other parts of the configuration, and we would always get the same instance. Is my understanding of this correct? Does spring do some magical rewriting of methods annotated with #Bean?
#Bean
public BasicAuthenticationEntryPoint entryPoint() {
BasicAuthenticationEntryPoint basicAuthEntryPoint = new BasicAuthenticationEntryPoint();
basicAuthEntryPoint.setRealmName("My Realm");
return basicAuthEntryPoint;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.exceptionHandling()
.authenticationEntryPoint(entryPoint())
.and()
.authorizeUrls()
.anyRequest().authenticated()
.and()
.httpBasic();
}
Yes, Spring does some magic. Check the Spring Docs:
This is where the magic comes in: All #Configuration classes are subclassed at startup-time with CGLIB. In the subclass, the child method checks the container first for any cached (scoped) beans before it calls the parent method and creates a new instance.
This means that the calls to #Bean methods are proxied via CGLIB and therefore the cached version of the bean is returned (a new one is not created).
The default scope of #Beans is SINGLETON, if you specify a different scope such as PROTOTYPE the call will be passed to the original method.
Please note that this is not valid for static methods. As per the spring docs:
Calls to static #Bean methods never get intercepted by the container, not even within #Configuration classes (as described earlier in this section), due to technical limitations: CGLIB subclassing can override only non-static methods. As a consequence, a direct call to another #Bean method has standard Java semantics, resulting in an independent instance being returned straight from the factory method itself.

Specific url for controller using #PathVariable in RequestMapping issue

I am facing some difficulties when trying to create a certain url for #RequestMapping in a spring controller.
First of all, because of the framework the project uses, there is a controller method mapped to the following url: "/{pageLabelOrId}"
Second, I have another controller method mapped to "/{pageName}.html". This works fine, meaning that if I try to access from browser "www.applicationUrl/something.html" this url if captured by the second method as is intended.
Now here is my problem. I must handle a somehow different but also similar url in a distinct method as follows: "/something-{parameter1}_{parameter2}_{parameter3}"
Trying to access "www.applicationUrl/something-1_2_3" will trigger the first controller: "/{pageLabelOrId}" instead of the desired one.
Handling this kind of url("/something-1_2_3") is a requirement and I cannot change it to something like "/something/{param1}/{param2}/{param3}" which I am sure it will work.
I have observed however, that writing a controller method mapped to "/something-{param}" will work and will capture my three parameters in one PathVariable(like "1_2_3") that I can parse afterwards by "_".
Does anyone have any idea of why does spring has this behavior and if I can somehow make it to work using three different path variables?
Spring 3.1+ uses a RequestMappingHandlerMapping to create RequestMappingInfo objects which map your controller handler methods to their corresponding #RequestMapping paths. When the DispatcherServlet receives a request, it uses the RequestMappingHandlerMapping again to determine which handler method should be used.
The way it is currently implemented, it finds all the registered RequestMappingInfo objects that match the request and then sorts them based on a number of rules, basically those defined in AntPathMatcher and AntPatternComparator.
You'll have to configure your RequestMappingHandlerMapping bean to use a custom PathMatcher with your own rules for comparing.
How you do this depends on how you are doing your configuration. If you use a #Configuration class, you can do
#Configuration
public class WebConfig extends WebMvcConfigurationSupport {
...
#Override
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
RequestMappingHandlerMapping mapping = super.requestMappingHandlerMapping();
mapping.setPathMatcher(pathMatcher()); // some PathMatcher bean
return mapping;
}
...
}
The RequestMappingInfo objects created by this RequestMappingHandlerMapping will internally use this PathMatcher. They will be sorted based on its Comparator.

Migration to Spring Annotated Controllers and traditional onSubmit method

I am trying to migrate from Spring 2.0 to Spring 3.0.
Previously I defined a controller MyController inheriting from SimpleFormController and have some logic written in the onSubmit method. All my controllers having the handler methods are inherited from MyController. Thus, the logic written in onSubmit of MyController used to get executed for all requests.
Now as I migrate to annotated controller wherein my controller is a simple pojo, how do I ensure the execution of onSubmit everytime? One way is to call onSubmit from all handler methods of all the controllers. This is cumbersome.
Can anyone suggest any feasible solution. As annotating formBackingObject with #ModelAttribute ensures the invocation for all requests, isn't there an analogy for onSubmit method?
If you want to perform the same action before each invokation of any annotated controller, you could use an interceptor. You can write your own interceptor by just implementing the preHandle method.
You will then need to register this interceptor in the DefaultAnnotationHandlerMapping or whatever Handler mapping you use to dispatch to your controllers.
Registering interceptors is explained in this article:
http://www.scottmurphy.info/spring_framework_annotation_based_controller_interceptors
Annotate the method you wish to invoke. The method signature is very flexible. Take a look at the docs for #RequestMapping
#RequestMapping(value={"/foo"}, method=RequestMethod.POST)
public String myMethod(many options for parameters) {...
Ok so if i understand correctly you want inheritance to continue to play a role in the stack when a request is handled by a controller. You can extend any class in an #RequestMapping annotated POJO but you will have to define an #override method to annotate it. All you do basically is call super with the arguments in the overriding method. If you extend an annotated class and both are declared as Controller then you will get an exception since the route will be defined more then once.
it would look like this
public class Pojo{
public String someBaseMethod(){
return "";
}
}
#Controller
public class ChildController extends Pojo {
#Override
#RequestMapping("/do_it")
public String someBaseMethod() {
return super.someBaseMethod();
}
}
A good case could be made to use composition over inheritance. I even suggest that you use the filtering mechanism instead if it can apply to perform common operations. AOP could also be a good tool.

Categories

Resources