Spring 3.1 M2: Spring MVC Enhancements |

This post focuses on what's new for Spring MVC in Spring 3.1 M2. Here are the topics:
- Code-based equivalent for the MVC namespace.
- Customizable @MVC processing.
- Programming model improvements.
A brief reminder that the features discussed here are in action at the Greenhouse project.
Code-based Configuration For Spring MVC
As Chris pointed out in his blog post last Friday, XML namespaces cut down configuration dramatically but also reduce transparency and sometimes flexibility. This holds true for the MVC namespace, which supports a number of customizations but not everything that's available. That means you are either able to use it or otherwise leave it. We believe code-based configuration has a solution for that and a path from simple to advanced.
Let's begin with this simple, familiar snippet:
<mvc:annotation-driven />
Although not required for using annotated controllers, <mvc:annotation-driven> does a number of useful things — it detects the presence of a JSR-303 (Bean Validation) implementation and configures data binding with it, it adds a JSON message converter if Jackson JSON library is available, and a few other things that can save quite a bit of configuration.
Now let's match that with code-based configuration:
@Configuration
@EnableWebMvc
public class WebConfig {
}
Here @EnableWebMvc imports an @Configuration class that matches the goodness of <mvc:annotation-driven>. As simple as that.
The next step is to use an attribute in <mvc:annotation-driven> perhaps to provide a FormattingConversionService, or to add a sub-element perhaps configuring message converters, or to use other MVC namespace elements like <mvc:interceptors>, <mvc:resources>, etc.
Let's see how to do all of that in code-based configuration:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addFormatters(FormatterRegistry registry) {
// register converters and formatters...
}
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
// add message converters...
}
@Override
public void configureInterceptors(InterceptorConfigurer configurer) {
configurer.addInterceptor(new AccountExposingHandlerInterceptor());
}
@Override
public void configureResourceHandling(ResourceConfigurer configurer) {
configurer.addPathMapping("/resources/**").addResourceLocation("/resources/");
}
// more @Override methods ...
}
Notice this time we've also sub-classed WebMvcConfigurerAdapter, a convenient base class with nothing but empty method implementations of the WebMvcConfigurer interface, which defines configuration callbacks for customizing the Spring MVC configuration. @Configuration classes that implement this interface are detected and given a chance to apply customizations. That's pretty much it.
The above provides parity with the MVC namespace in a way that is arguably more transparent. You can use familiar Java IDE shortcuts to explore both the WebMvcConfigurer interface and the @Bean methods of the imported @Configuration class.
What about more advanced customizations? Well, this is as far as we can go with the MVC namespace. For code-based configuration, in the next (RC1) release, you'll be able to take the above example as is, drop the imported configuration (i.e. remove @EnableWebMvc) and switch to a base class that contains @Bean methods you can override. This means you can use Spring MVC code-based configuration knowing that any level of customization is possible — either through a simple callback mechanism or by extending directly from the class providing the actual configuration.
Here is a look at the web configuration in Greenhouse.
Customizable @MVC Processing
The @MVC programming model has been very successful enabling flexible controller method signatures. Yet many of you have asked for the underlying @MVC support classes to be more customizable. In response we've rolled a new set of @MVC support classes that give you more power and give us a better foundation to build on.
Before annotations, the Controller was the processing endpoint. With annotations the individual controller method became the endpoint complete with its own request mappings. Following this logic a HandlerMapping should not be limited to selecting a controller but should pick a controller method instead. Hence it will make sense that we've added a HandlerMethod abstraction and an AbstractHandlerMethodMapping for handler mappings that can select a HandlerMethod.
These are the new @MVC support classes built around the HandlerMethod abstraction:
RequestMappingHandlerMappingRequestMappingHandlerAdapterExceptionHandlerExceptionResolver
As a result we now have a single point of selection in the handler mapping, the handler adapter knows exactly which handler method was selected, and so do other components. For example many of you requested to have interception around the invocation of a handler method, a gap that is now closed. Another less obvious consequence is the freedom to map the same URL across different controllers as long as the mapping differs in some other way (e.g. HTTP method).
Beyond request mapping, the execution of a controller method requires resolving method arguments (@RequestParameter, @ModelAttribute, etc) and handling return values (@ResponseBody, @ModelAttribute, etc.). The new @MVC support classes expose a pluggable mechanism where implementations of HandlerMethodArgumentResolver and HandlerMethodReturnValueHandler can be plugged in to resolve every method argument and handle every return value. You have full control over that — you can either design your own argument types and return value types or customize the processing of the built-in ones. More details on that in a subsequent post.
To try the new @MVC support classes simply upgrade to Spring 3.1 M2. Both the MVC namespace and @EnableWebMvc configure them. Or if you have your own configuration just swap these:
DefaultAnnotationHandlerMapping->RequestMappingHandlerMappingAnnotationMethodHandlerAdapter->RequestMappingHandlerAdapterAnnotationMethodExceptionResolver->ExceptionHandlerExceptionResolver
A note on compatibility: The existing support classes will continue to be available. However, we recommend that you switch going forward. For instance all the programming model improvements in the next section are only available that way. The new classes should be a drop-in replacement for the most part but there are two noteworthy differences. One, you can't combine any of the existing AbstractUrlHandlerMapping types (e.g. SimpleUrlHandlerMapping) with the new handler adapter, which expects a HandlerMethod and not a handler. Two, you can't rely on the method name when two @RequestMapping methods match equally to a request.
Programming Model Improvements
This section lists programming model improvements introduced in the new @MVC support classes.
1. Declared @PathVariable arguments are now automatically added to the model. For example this:
@RequestMapping("/develop/apps/edit/{slug}")
public String editForm(@PathVariable String slug, Model model) {
model.addAttribute("slug", slug);
// ...
}
is replaced by:
@RequestMapping("/develop/apps/edit/{slug}")
public String editForm(@PathVariable String slug, Model model) {
// model contains "slug" variable
}
2. Redirect strings support URI templates expanded with variables from the model (including declared @PathVariables). For example this:
@RequestMapping(
value="/groups/{group}/events/{year}/{month}/{slug}/rooms",
method=RequestMethod.POST)
public String createRoom(
@PathVariable String group, @PathVariable Integer year,
@PathVariable Integer month, @PathVariable String slug) {
// ...
return "redirect:/groups/" + group + "/events/" + year + "/" + month + "/" + slug;
}
is replaced by:
@RequestMapping(
value="/groups/{group}/events/{year}/{month}/{slug}/rooms",
method=RequestMethod.POST)
public String createRoom(
@PathVariable String group, @PathVariable Integer year,
@PathVariable Integer month, @PathVariable String slug) {
// ...
return "redirect:/groups/{group}/events/{year}/{month}/{slug}";
}
3. URI template variables are supported in data binding. For example this:
@RequestMapping("/people/{firstName}/{lastName}/SSN")
public String find(Person person,
@PathVariable String firstName,
@PathVariable String lastName) {
person.setFirstName(firstName);
person.setLastName(lastName);
// ...
}
is replaced by:
@RequestMapping("/people/{firstName}/{lastName}/SSN")
public String search(Person person) {
// person.getFirstName() and person.getLastName() are populated
// ...
}
4. Consumable and producible media types can be specified via @RequestMapping. For example this:
@RequestMapping(value="/pets", headers="Content-Type=application/json")
public void addPet(@RequestBody Pet pet, Model model) {
// ...
}
is replaced by:
@RequestMapping(value="/pets", consumes="application/json")
public void addPet(@RequestBody Pet pet, Model model) {
// ...
}
Besides being shorter the above returns NOT_ACCEPTABLE (406) if the URL matches but the input media type doesn't.
5. For producible media types this:
@Controller
@RequestMapping(value = "/pets/{petId}", headers="Accept=application/json")
@ResponseBody
public Pet getPet(@PathVariable String petId, Model model) {
// ...
}
is replaced by:
@Controller
@RequestMapping(value = "/pets/{petId}", produces="application/json")
@ResponseBody
public Pet getPet(@PathVariable String petId, Model model) {
// ...
}
The above returns a NOT_SUPPORTED_MEDIA_TYPE (415) if the URL matches but the acceptable media type doesn't.
Summary
There is a lot that's new in this milestone release. I encourage everyone to try the changes and provide feedback ahead of the RC1 and GA releases.
I would also like to turn your attention to another on-going effort to provide integration test support to Spring MVC applications. For server-side test support see the spring-test-mvc project available on Github. For client-side support check the Spring Social project or track the following JIRA ticket SPR-7951.
Similar Posts
- Using a Hybrid Annotations & XML Approach for Request Mapping in Spring MVC
- Spring MVC 3.2 Preview: Chat Sample
- Annotated Web MVC Controllers in Spring 2.5
- REST in Spring 3: @MVC
- Adding an Atom view to an application using Spring's REST support




Bill says:
Added on June 13th, 2011 at 2:33 pmAdding regex quantifier support to @RequestMappings will help with @MVC applications. A patch is attached to https://jira.springsource.org/browse/SPR-7787, it just needs applying.
Oscar Westra van Holthe - Kind says:
Added on June 14th, 2011 at 2:11 amGood stuff: especially the interfaces HandlerMethodArgumentResolver and HandlerMethodReturnValueHandler are very powerfull (as blogged here: http://blog.42.nl/articles/leveraging-the-spring-mvc-3.1-handlermethodargumentresolver-interface ).
A question though:
Is it possible to add multiple resource paths? The code now looks af if this:
@Override
public void configureResourceHandling(ResourceConfigurer configurer) {
configurer.addPathMapping("/css/**").addResourceLocation("/css/");
configurer.addPathMapping("/images/**").addResourceLocation("/images/");
}
Results in one resource mapping, serving stylesheets as both /css/main.css and /images/main.css, and images as both /images/picture.jpg and /css/picture.jpg
Oscar
Javier says:
Added on June 14th, 2011 at 3:26 amThese changes are very exciting as well as the next new release 3.1 in general.
I specially like the code configuration. Yes, the mvc namespace is very simply and powerful, but I'd rather to have some direct control over this configuration, and the new annotations allow me to do that. Specially when debugging comes into play.
But I think MVC, and server web developement in general, lacks of one important thing: a WYSIWYG tool.
I tried Wavemaker, a recently acquired by VMWare tool. I didn't like because it was a little bit intrusive because it uses a propietary code, a central server that implies you need to add an aditional JAR to the server.
However, I loved the way they build the web sites and I could see that it's really possible to create a server side code automatically. Even for specific Application Servers and Databases (as far as I know it suports DB2 and even Websphere)
Have you ever consider to create something like that? Or even better, to modify Wavemaker, now that you own this tool.
Rossen Stoyanchev (blog author) says:
Added on June 14th, 2011 at 3:32 am@Bill, we'll take a look.
@Oscar, thanks for providing a link. The ResourceConfigurer creates a single ResourceHttpRequestHandler mapped to all the paths you specify and looking through all the specified locations. That should work even in your example, shouldn't it? If you'd like to create a separate ResourceHttpRequestHandler however, you could create another ResourceConfigurer from an @Bean method, add the paths and locations to it, call getUrlHandlerMapping() to obtain the HandlerMapping, and return that from the @Bean method.
Jeremy Grelle (blog author) says:
Added on June 14th, 2011 at 11:54 am@Javier,
You are right on target, we have plans to evolve WaveMaker to produce more "idiomatic" modern Spring MVC RESTful @Controllers on the server side to produce and consume JSON, as opposed to the slightly foreign-looking JSON-RPC approach that it currently uses. We have a few smaller releases to get done first, but keep an eye out for significant improvement along these lines in our next major release.
Oscar Westra van Holthe - Kind says:
Added on June 15th, 2011 at 1:26 am@Rossen: thank you, the HandlerMapping @Bean is a good idea and it works nicely
Two caveats for those who want to do the same:
1. ResourceConfigurer#getUrlHandlerMapping() is protected, so create a subclass to widen its scope.
2. Ensure you create a ServletContext bean (e.g. a MockServletContext) for your unit tests.
amertum says:
Added on June 15th, 2011 at 2:20 amQuestion !
How do you do data binding of firstname and lastname if they contains a dash "-" ?
@RequestMapping("/people/{firstName}-{lastName}/SSN")
public String find(Person person,
@PathVariable String firstName,
@PathVariable String lastName) {
// …
}
I really don't like these kind of automation when there is no powerful configuration aside.
Rossen Stoyanchev (blog author) says:
Added on June 15th, 2011 at 3:25 am@Oscar, in response to your comments we've made some improvements to make it easier to register multiple resource handlers. See https://jira.springsource.org/browse/SPR-8454 for more details.
Rossen Stoyanchev (blog author) says:
Added on June 15th, 2011 at 3:40 am@amertum, starting with @PathVariable arguments only:
@RequestMapping("/people/{firstName}-{lastName}/SSN")
public String find(@PathVariable String firstName, @PathVariable String lastName) {
}
Hopefully the above makes sense. Now instead of using @PathVariables, imagine applying the values extracted from the URL (i.e. firstName=".." and lastName="..") to a target object via data binding.
@RequestMapping("/people/{firstName}-{lastName}/SSN")
public String find(@ModelAttribute Person person) {
}
If the target object has firstName and lastName fields, they will be populated accordingly. You can also add an @Valid annotation and use a BindingResult argument to see the results of data binding as usual.
You can choose whether to use individual @PathVariable arguments or a @ModelAttribute argument.
HTH
Rossen Stoyanchev (blog author) says:
Added on June 15th, 2011 at 9:13 am@amertum, I think I misinterpreted your comment by thinking you referred to the "-" in the URI template but you meant a "-" in the first or last names. Good point! I've corrected the example replacing the "-" with "/".
punter says:
Added on June 15th, 2011 at 2:26 pmHey Rossen
I Just started using Spring MVC. I was trying to figure out the best possible way to overload the "produces" attribute for RequestMapping to allow application/json | application/xml responses. It would be much appreciated if you could please point me to the right direction.
Thanks.
mezza9 says:
Added on June 16th, 2011 at 2:16 amHey Rossen,
It is nice to have all the stuff configured in your code now. So I like this. And I gave a try to the configuration and stucked with a problem, could you please have a look on that here:
http://forum.springsource.org/showthread.php?110756-Spring-MVC-3.1.0-M2-WebApplicationInitializer-code-based-approach-problem
Thanks in advance.
Rossen Stoyanchev (blog author) says:
Added on June 16th, 2011 at 5:42 am@punter, you can specify multiple producible media types for a method. See the javadoc for the @RequestMapping produces() attribute.
@mezza9, I'm glad you like the code-based configuration option. See my response in the forum.
amertum says:
Added on June 16th, 2011 at 9:40 am@rossen : Thanks. It is less common to have a slash in its name
Sorry for my not very detailed comment.
Piotr says:
Added on June 28th, 2011 at 8:10 amAre @RequestParameter also automatically added to the model?
Rossen Stoyanchev (blog author) says:
Added on June 28th, 2011 at 8:43 amNo, request params are not added automatically to the model.
Piotr says:
Added on June 28th, 2011 at 9:11 amAny explanation why not?
Rossen Stoyanchev (blog author) says:
Added on June 28th, 2011 at 10:36 amEven with path variables it's not always clear they should be added to the model automatically. Most obvious are cases where the model is processed in some automated fashion – e.g. MappingJacksonJsonView, MarshallingView, and RedirectView. We do handle those cases correctly but for other view types we make the assumption that URI template variables accessed as @PathVariables in your controller method are likely to needed in the view. I can imagine that assumption isn't always true but it seems reasonably close. It's much less obvious to me that request parameters from the current request should be automatically added to the model. In fact that could even lead to side effects since data binding relies on request parameters.
free online driving games says:
Added on June 30th, 2011 at 9:41 pmAny explanation
Chris Roberts says:
Added on July 6th, 2011 at 9:46 pmGreat improvements, especially around @PathVariables and data binding.
One thing I've needed in the past is the ability to choose controller methods based on the value of incoming request parameters. For example, I might have a parameter named "mode" that is either set to "edit" or "delete" so that I can reuse the same JSP code for two different front-end user functions. The idea is that one controller method would be called if the "mode" request parameter were "edit", and another if it's "delete". The @RequestParam annotation would look something like @RequestParam("mode=edit") or @RequestParam("mode=delete").
Is something like this already supported? Or being planned? Or should I enter it into Jira?
Thanks!
Oscar Westra van Holthe - Kind says:
Added on July 7th, 2011 at 1:09 am@Chris: This is supported, using the 'params' attribute of the @RequestMapping annotation.
For example: the following method annotations select the same URL (the one the controller is mapped to), but each is mapped to a different value of the request parameter 'mode'. Each is applied to a different controller method.
@RequestMapping(value = "", method = RequestMethod.GET, params = "mode=edit")
@RequestMapping(value = "", method = RequestMethod.GET, params = "mode=delete")
Mark says:
Added on July 12th, 2011 at 6:29 pmHi,
Not sure if this is the right place for this. But was interested in using the new @RequestMapping(produces="") functionality to mess around with some REST type functionality so knocked up a simple controller with the following method;
@RequestMapping(value = "/{orderNumber}", method = RequestMethod.GET, produces = "application/vnd.org.restbucks.order xml")
@ResponseBody
public OrderDto getOrder(@PathVariable("orderNumber") Long orderNumber) throws NotFoundException
{
return new OrderDto("Latte", 10.0d);
}
Everything worked as expected when I fired up Tomcat and made a request via RestClient with the appropriate Accept Header. Then I wanted to test the scenario where the Media Type can't be matched, so I made the request with no Accept header expecting to get a NOT_SUPPORTED_MEDIA_TYPE(415) back – but I got the same response as before, i.e. an XML version of OrderDto with a Content-type="application/vnd.org.restbucks.order xml" response header.
So, determined to provoke a 415 response I added a second method with the same URL signature;
@RequestMapping(value = "/{orderNumber}", method = RequestMethod.GET, produces = "application/vnd.org.restbucks.order-V2 xml")
@ResponseBody
public OrderDto getOrderV2(@PathVariable("orderNumber") Long orderNumber) throws NotFoundException
{
return new OrderDto("Latte-V2", 1110.0d);
}
Everything worked fine when requesting with the appropriate Accept header. However, when I left the accept header out in order to try and provoke a 415 response I got an Internal Server Error(500) with this stacktrace contained in the body;
java.lang.IllegalStateException: Ambiguous handler methods mapped for HTTP path 'http://localhost:8080/restbucks/api/order/1': {public org.restbucks.version.version1.dto.OrderDto org.restbucks.server.endpoint.OrderController.getOrder(java.lang.Long) throws org.restbucks.model.exception.NotFoundException, public org.restbucks.version.version1.dto.OrderDto org.restbucks.server.endpoint.OrderController.getOrderV2(java.lang.Long) throws org.restbucks.model.exception.NotFoundException}
org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.lookupHandlerMethod(AbstractHandlerMethodMapping.java:280)
org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.getHandlerInternal(AbstractHandlerMethodMapping.java:225)
org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.getHandlerInternal(AbstractHandlerMethodMapping.java:1)
org.springframework.web.servlet.handler.AbstractHandlerMapping.getHandler(AbstractHandlerMapping.java:288)
…
As I say, not sure this is the right forum to bring this up or if this is a know issue.
Mark.
Rossen Stoyanchev (blog author) says:
Added on July 13th, 2011 at 3:30 amMark, without an Accept header any producible media type will match – i.e. same as requesting '*/*'. Try requesting a media type that doesn't match. You should get the expected response.
Mark says:
Added on July 13th, 2011 at 4:30 amHi Rossen,
Thanks for getting back. Yeah that makes sense – kinda thought that was the case. Em, not sure I'd agree with that as being a good idea as unwary clients (we've lots and lots of them) could code to that omitting the Accept header, get XML back and think Happy Days.
Then when we introduced a new V2 version their code would break – I know, procedures, staging environments, sandboxes, RTFM etc. But the fact of the matter is it would still happen – so we'd have to code some kinda of "missing Accept" validation into our V1 code from the start … something I feel that should be done for me by the framework – explicitly or optionally. That's just a personal opinion and I'm sure lots of people would disagree – and most probably the HTTP spec would back them up.
However, what I'd be more worried about is the stacktrace being thrown when there's 2 URL/MediaType versions and no Accept is supplied. I'd be worried about the level of internal code detail this is providing – and yes this all could be managed by an Error Handler, but I think a better exception could be thrown in this scenario in the first place.
Regards,
Mark.
Regards,
Mark.
Rossen Stoyanchev (blog author) says:
Added on July 13th, 2011 at 7:58 amIf the request contains an Accept header, then it must match. Not having an Accept header in this case means you will accept whatever the server returns. I think that fits the element of least surprise principle.
It also fits Postel's law of being conservative with what you do but liberal with what you accept from others. The "produces" condition indicates what the method is designed to return. Unlike "consumes" it doesn't depend on a specific client request input. If the client didn't specify an Accept header, technically nothing prevents the method from returning what it can.
By the way it's unlikely the client will succeed anyway since a mismatch in the returned content type (json vs xml) will likely cause a problem.
For what it's worth this behavior is consistent with JAX-RS.
We could surely prevent this specific exception but there are many other runtime exceptions and errors that could occur in your code or views all of which would send a stack trace to the client. You will need a stopgap measure such as an ExceptionResolver or an entry in web.xml regardless to ensure that never happens.
Mark says:
Added on July 13th, 2011 at 9:29 amYes agreed, but just thought that a kinda "default" option to the produces might be nice so I could guarantee that a V1 is always returned in the no Accept supplied scenario – rather than having to code around this scenario myself. Doesn't really matter, validation can be performed to protect against this.
Actually, what I meant about the stacktrace was not so much about the Exception itself, definitely would implement a Exception Handler for this and all others, but the content it contains. What I meant is it's a little scary that this kinda info should be encapsulated in an Exception. Again, just a personal opinion – I know good practice would ensure that it would never leak to "users" but just thought not such a great idea having it there in the first place.
Anyway, cheers for getting back. Really like all the new features.
Serge says:
Added on August 19th, 2011 at 1:46 amHello,
I am attempting to test some web services which return JSON but it seems the the JSON handler is not auto added despite Jackson being on the classpath and using ?
@RequestMapping(value = "/biz/{deviceId}", method = RequestMethod.GET, produces = "application/json")
public @ResponseBody Business getBusinessContext(@PathVariable Long deviceId) {
return bizSvc.loadBusiness(deviceId);
}
Has anyone been able to test a JSON response using @ResponseBody ?
Thanks
robd says:
Added on August 22nd, 2011 at 9:36 amI see that WebMvcConfigurerAdapter has changed somewhat in the latest SNAPSHOT.
New method:
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
Old method:
public void configureResourceHandling(ResourceConfigurer configurer) {
configurer.addPathMapping("/resources/**").addResourceLocation("/resources/");
}
Kamil Sevecek says:
Added on September 14th, 2011 at 2:17 amHello
When I do evangelizing work about Java technologies, I like to have things logical.
Spring MVC's DispatcherServlet currently reads DispatcherServlet.properties with default beans that should be configured in Spring MVC context.
If you define a bean of the same interface manually, the original beans from DispatcherServlet.properties of that interface will be ignored.
Now, that was OK for the Spring MVC prior to . But overrides half of the default beans already. Could we change it so that it overrides (duplicates) all beans from the DispatcherServlet.properties so that we could say: "What makes Spring MVC context file different, is the declaration of , not just the fact, that it's loaded by the DispatcherServlet which magically declares something. Always use and DispatcherServlet.properties is deprecated (but will still work until some time)."
Rossen Stoyanchev (blog author) says:
Added on September 14th, 2011 at 2:44 amKamil I didn't understand your question.
The DispatcherServlet.properties holds framework defaults.
If you declare your own beans of a specific type you override the defaults.
The MVC namespace and @EnableWebMvc declare some default beans hence overriding the defaults.
Kamil Sevecek says:
Added on September 14th, 2011 at 3:06 amUnfortunatelly I used tags mvc:namespace and it was removed from the post. I will post it again:
Hello
When I do evangelizing work about Java technologies, I like to have things logical.
Spring MVC's DispatcherServlet currently reads DispatcherServlet.properties with default beans that should be configured in Spring MVC context.
If you define a bean of the same interface manually, the original beans from DispatcherServlet.properties of that interface will be ignored.
Now, that was OK for the Spring MVC prior to mvc:namespace. But mvc:annotation-driven overrides half of the default beans already. Could we change it so that it overrides (duplicates) all beans from the DispatcherServlet.properties so that we could say: "What makes Spring MVC context file different, is the declaration of mvc:annotation-driven, not just the fact, that it's loaded by the DispatcherServlet which magically declares something. Always use mvc:annotation-driven and DispatcherServlet.properties is deprecated (but will still work until some time)."
How about that?
Kamil Sevecek says:
Added on September 14th, 2011 at 3:16 amShort explanation: What I meant is that I didn't like the feature of Spring MVC that the context magically declars beans which were not visible in the config file. (I know they come from DispatcherServlet.properties, but still…)
It can be elegantly solved by using mvc:annotation-driven.
Rossen Stoyanchev (blog author) says:
Added on September 14th, 2011 at 3:43 amI believe, it is important to have some basic default configuration even if you have no (or very few) bean declarations. That is the purpose of DispatcherServlet.properties. The intent of the MVC namespace and Java config on the other hand is to provide you more extensive defaults for the @MVC programming model.
You have a good point that indeed in Spring 3.0.x, use of the MVC namespace turned off some DispatcherServlet.properties defaults (e.g. BeanNameUrlHandlerMapping) that are not as commonly used with annotated controllers. In Spring 3.1 the MVC namespace and the Java config aim to fill that gap by ensuring we don't turn off DispatcherServlet.properties defaults. For example see the Java doc for WebMvcConfigurationSupport.java.
That doesn't mean DispatcherServlet.properties will be or needs to be deprecated. As I mentioned I do believe it's important to have out-of-the-box default settings.
Kamil Sevecek says:
Added on September 14th, 2011 at 4:41 amSo why do you not just override all bean declarations in mvc:annotation-driven (not just a couple of them)? That would be sufficient for me as I could always say: "Look where the beans come from" and don't need to look at two places but just to the mvc:annotation-driven tag Handler.
And that would solve the (in my opinion) redundant WebMvcConfigurationSupport as well.
Generally I like the clean design of Spring Framework that if you don't have written anything in your context.xml, you really don't have anything declared.
Rossen Stoyanchev (blog author) says:
Added on September 14th, 2011 at 4:53 amThat is what I said. In 3.1 we're providing all DispatcherServlet.properties defaults in the MVC XML namespace (i.e. mvc:annotation-driven) and in the Java config equivalent of the MVC namespace (i.e. WebMvcConfigurationSupport). For what it's worth the Java config is a better place to point people to because it's more transparent — the code in WebMvcConfigurationSupport is readable and suitable as a base class while the code behind mvc:annotation-driven is infrastructure code that isn't nearly as readable.
Kamil Sevecek says:
Added on September 14th, 2011 at 7:05 amJust to finish off this one: No, mvc:annotation-driven does not define ALL defaults (such as FixedThemeResolver) which is a shame. If it did, it would be much cleaner. I know it would have to be conditional so as to behave the same way as the defaults from DispatcherServlet.properties, but as I'm saying it would be cleaner as the defaults would be on 1 place.
I think we understand each other, I made my point so thank you for your answer.
Rossen Stoyanchev (blog author) says:
Added on September 14th, 2011 at 7:51 amYes, you're right. The MVC namespace does not repeat every default in DispatcherServlet.properties. It only ensures it doesn't turn off additional HandlerMappings, HandlerAdapters, and HandlerExceptionResolvers. But for others like ThemeResolver it relies on the underlying defaults in DispatcherServlet.properties.
Effectively you get a superset of the DispatcherServlet defaults but it's not necessarily from one place. We could update the javadoc of WebMvcConfigurationSupport (and AnnotationDrivenBeanDefinitionParser) to list the defaults you get indirectly via DispatcherServlet.properties. That would make it easier for someone not familiar with DispatcherServlet.properties.
Harry Lascelles says:
Added on November 8th, 2011 at 9:15 amHi Rossen,
All looks good, but there's a problem adding a new MessageConverter. The method addDefaultHttpMessageConverters in WebMvcConfigurationSupport is doc'd to be overridable, but has been marked as final (in RC1).
I want to add a Gson JSON handler (since it is less invasive for design of immutable domain objects) without having to redeclare all the other handlers.
Can you removed the final marking?
Thanks!
Harry
Rossen Stoyanchev says:
Added on November 8th, 2011 at 10:09 am@Harry, you can override configureMessageConverters(List). As the javadoc indicates adding to the list there turns off the defaults so using that method overrides the defaults. If you still want the built-in defaults added for example after your converter, you can use the addDefaultHttpMessageConverter. Hopefully this works for you.
Harry Lascelles says:
Added on November 8th, 2011 at 10:22 amGreat, got it… just the doc that needs updating I suppose.
Thanks very much!
Harry
Rossen Stoyanchev says:
Added on November 8th, 2011 at 11:12 amYes, indeed. Will update it today. Thanks.
nw60312 says:
Added on December 14th, 2011 at 11:20 amQuestion on the RequestMapping consumes and produces attributes. It looks like these only work with headers and using file extensions like in the ContentNegotiatingViewResolver isn't possible. Is that the case?
It would be great if the framework could have a unified strategy for dealing with this both for request and view mapping.
Rossen Stoyanchev (blog author) says:
Added on December 14th, 2011 at 2:24 pmThe consumes and produces conditions support headers only. There is work planned for 3.2 in this area. See https://jira.springsource.org/browse/SPR-8410.
Kaizer says:
Added on January 11th, 2012 at 12:21 pmHi Rossen,
I am using Spring 3.1 on my project and wanted a feature similar to the end-point documentation example you created as part of the spring mvc 3.1 update. However, we are using xml based configuration and the Autowiring of the RequestMappingHandlerMapping instance fails in this case, throwing an exception saying no candidate was found.
Strangely, it works when I have a BeanPostProcessor instance (which I added to see which beans were getting created).
Any ideas on what could be going wrong?
Thanks.
Kaizer
Rossen Stoyanchev (blog author) says:
Added on January 11th, 2012 at 3:53 pmKaizer, by xml based config do you mean the mvc namespace? In which case I'm not sure what you mean by the "autowiring of the RequestMappingHandlerMapping". I suggest posting a question on the Spring Web forum showing the relevant parts of the configuration and the stacktrace.
lyon.yao says:
Added on February 3rd, 2012 at 2:32 amhello
i do it in Eclipse,i want to user ModeAndView and it is get a request url view
Rich Glazerman says:
Added on February 17th, 2012 at 6:45 pmI'm having trouble with Spring truncating my data, and I believe it's due to Suffix Pattern Matching. What's the best way for me to configure mvc:annotation-driven so that I can turn suffix pattern matching of on the RequestMappingHandlerMapping?
My function looks like this:
@RequestMapping(value = "/user/{tid}/email/{emailAddress}", method = RequestMethod.GET)
public void doGetEmailAddress(@PathVariable String tid, @PathVariable String emailAddress,
@RequestParam String authid, HttpServletResponse response) {
and when I pass a full email address "blah@blah.com", I only get "blah@blah" as my emailAddress parameter.
Thanks,
Rich
Rossen Stoyanchev (blog author) says:
Added on February 22nd, 2012 at 10:45 amRich, see the section on configuring Spring MVC including advanced customizations.
Rich Glazerman says:
Added on February 22nd, 2012 at 11:38 amRossen,
I added the "WebConfig" class to my class, but get the following errors in my tests:
com.turner.ids.application.ApplicationControllerTest: Error creating bean with name 'defaultServletHandlerMapping' defined in class path resource [com/turner/ids/web/WebConfig.class]: Instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public org.springframework.web.servlet.HandlerMapping org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport.defaultServletHandlerMapping()] threw exception; nested exception is java.lang.IllegalArgumentException: A ServletContext is required to configure default servlet handling
I have not found any details on fixing this in my searches… here is my config class:
@Configuration
public class WebConfig extends WebMvcConfigurationSupport {
@Override
@Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
final RequestMappingHandlerMapping requestHandler = super.requestMappingHandlerMapping();
requestHandler.setUseSuffixPatternMatch(false);
return requestHandler;
}
}
Rossen Stoyanchev (blog author) says:
Added on February 22nd, 2012 at 7:21 pmRich, please use the forums or JIRA as necessary to resolve problems not related to this blog post. From a brief look, as the error message says a ServletContext is required. It sounds like you're running a unit test and probably haven't provided a ServletContext to the WebMvcConfigurationSupport base class.
Thomas Bruyelle says:
Added on March 2nd, 2012 at 6:57 amAbout the WebConfig.class example from the Greenhouse project [1], I don't understand why they add the MappingJacksonHttpMessageConverter in the configureMessageConverters method.
I thought that MappingJacksonHttpMessageConverter was automatically added when the class is annotated with @EnableWebMvc. Am I wrong ?
[1] https://github.com/SpringSource/greenhouse/blob/master/src/main/java/com/springsource/greenhouse/config/WebConfig.java
Rossen Stoyanchev (blog author) says:
Added on March 2nd, 2012 at 9:36 am@Thomas, it is automatically added along with a number of others. Configuring it explicitly turns off the ones added by default.
Thomas Bruyele says:
Added on March 2nd, 2012 at 10:30 amThanks Rossen, I saw the behaviour in WebMvcConfigurationSupport.getMessageConverters()
Bob says:
Added on March 26th, 2012 at 11:37 pmHi,
I am working on REST service with "application/xml" as req and res type.
but when I invoke the service, i get a 415 error. Can you please give me some pointers on how to handle it.
thanks,
Bob
Kalichar says:
Added on April 9th, 2012 at 9:09 pmHi Rossen,
With Spring MVC 3.1. is there a way to support a Hybrid as you have described in a previous blog?
http://blog.springsource.org/2008/03/23/using-a-hybrid-annotations-xml-approach-for-request-mapping-in-spring-mvc/
I have a Controller that I want to map to a url based of some configuration parameter. With annotations one has to provide a static value.
Rossen Stoyanchev (blog author) says:
Added on April 10th, 2012 at 8:17 amKalichar, the new @MVC classes don't support this way of mapping requests. The old ones do and are still available in case you want to use them. However, keep in mind they don't get any new features.
Also the new RequestMappingHandlerMapping supports custom request mapping conditions. It might useful to describe what you are trying to do and see if there are any other possibilities. Just not here, maybe in a forum post.
Kishore says:
Added on May 30th, 2012 at 4:26 amHi,
Can anybody suggest the possibility of the wavemaker widgets integrate with Spring MVC (dispatcher servlet based processing).
Thanks
Kishore
sacool says:
Added on June 1st, 2012 at 5:42 amorg.springframework.web.servlet.DispatherServlet
jar version 3.1.1 release.
at line 950 render method.That forward a resource. When forward a jsp, and in the jsp throw a exception.The ExceptionResolver can not catch the exception.
I do not known if is a bug. And if i want to catch the exception to deal, how to do it. thanks.
My English is spool .please forgive me
Stefan says:
Added on July 19th, 2012 at 6:55 amI'm seeing some strange behavior since updating to Spring 3.1 which I suspect has something to do with the new automatic URI template expansion feature. For some reason if my controller method declares to return a String everything works as expected. If I change that to Object, however, my view name get's expanded, even if it's no redirect and even if I don't use curly braces in my view name:
@RequestMapping("/some/{thing}")
public String read(@PathVariable String thing) {
// …
return "thing";
}
Correctly loads my "thing" template (using Freemarker here), but
@RequestMapping("/some/{thing}")
public Object read(@PathVariable String thing) {
// …
return "thing";
}
with a given request URI "/some/interesting" will try to lookup a template named "interesting".
Is this intentional?
Rossen Stoyanchev (blog author) says:
Added on July 23rd, 2012 at 7:22 amStefan, I believe this is most likely due to SPR-9218, which we missed backporting to Spring 3.1.x. I've now created SPR-9622 to correct that.
Stefan says:
Added on July 24th, 2012 at 12:27 am@Rossen: Thanks. I dug a little bit deeper myself and realized, that it's not the URI expansion but rather the different interpretation of the return value of the request method. I changed all my methods to return ModelAndView methods which does the trick for me now. Would be nice to see a fix for SPR-9622 in 3.1 though.
kheralalit says:
Added on March 26th, 2013 at 6:52 pmHi, i have basic knowledge of servlets , jsp and beans.
I have developed few applications using core servlets and jsp.
What i need to understand spring mvc. what are the pre-requirements for spring mvc? do i need to work on core spring or directly i can start with spring mvc module?? i have an interview within 4 days from now
Steve says:
Added on March 27th, 2013 at 8:43 pmReally great stuff. You guys keep making it simpler to produce quality, clean web apps. Keep it up!
I am a little curious when explicitly setting the response content-type (eg. 'produces="application/json"') is necessary in the request mapping when used with @ResponseBody. I have never explicitly specified the response content-type for my JSON services. Is this just to disable Spring from serving other content-types, like xml if requested in the request headers?
Thanks again for the informative post!
Rossen Stoyanchev (blog author) says:
Added on March 28th, 2013 at 5:25 amHi Steve, the produces condition guarantees the method will serve that content type and nothing else. This is also true if the request is for any content type (wildcard) or does not request any content type.
Of course in 3.2 we also have the ContentNegotiationManager which allows setting the default content type (through the FixedContentNegotiationStrategy) on all incoming requests.
Steve says:
Added on March 28th, 2013 at 6:47 amThank you Rossen. Makes perfect sense.