Top 5 enhancements of Spring MVC 3.1

After many months of development, Spring 3.1 has been finally released. The release is shipped with some exciting features like caching abstraction, bean profiles and container configuration simplifications. However, in this blog post I will describe my top 5 enhancements of Spring MVC 3.1.

1. Flash attributes support

Flash attributes are used to store attributes between requests and  are used mostly in Post/Redirect/Get pattern. Prior to Spring 3.1 some additional (repeatable) steps were required to utilize flash attributes in Spring MVC based applications:
  • Create or copy FlashMap object to hold flash attributes
    			public class FlashMap implements Serializable  {
    				// implementation omitted
    			}
    		
  • Create or copy FlashMapFilter to your project
    			public class FlashMapFilter extends OncePerRequestFilter {
    				// implementation omitted
    			}
    		
  • Include FlashMapFilter in web.xml
  • Put flash attributes in the controller when needed
    			@PreAuthorize("hasRole('ROLE_USER')")
    			@RequestMapping(value = Routing.SOME_ROUTING, method = RequestMethod.POST)
    			public String processForm(@Valid Form form, BindingResult result) {
    
    				// process the form
    				// ...
    
    				// add flash attribute
    				FlashMap.addAttribute("message", "Form processed");
    
    				// redirect
    				return RoutingHelper.redirect(Routing.SOME_OTHER_ROUTING);
    			}
    		
With Spring 3.1 flash attributes support is enabled by default. No additional configuration is required. @Controller method accepts the argument of a type RedirectAttributes. RedirectAttributes is an interface that extends from standard Spring MVC Model interface and it may be used to store flash attributes that will be available after the redirection.
	@PreAuthorize("hasRole('ROLE_USER')")
	@RequestMapping(value = Routing.SOME_ROUTING, method = RequestMethod.POST)
	public String processForm(@Valid Form form, BindingResult result, RedirectAttributes redirectAttributes) {

		// process the form
		// ...

		// add flash attribute
		redirectAttributes.addFlashAttribute("message", "Form processed");

		// redirect
		return RoutingHelper.redirect(Routing.SOME_OTHER_ROUTING);
	}

2. @Validated annotation with support for JSR-303 validation groups

Spring MVC Bean Validation support has been extended with a new @Validated annotation that provides support of JSR 303 validation groups. A group defines a subset of constraints that is validated for a given object graph. Each constraint declaration may define the group or the list of groups it belongs to.
	public class User {
		@NotNull
		private String name;

		@NotNull(groups = { Simple.class })
		private String address;

		@NotNull(groups = { Simple.class, Extended.class })
		private String licenceType;

		@NotNull(groups = { Extended.class })
		private String creditCard;
	}
 
	public interface Simple {

	}

	public interface Extended {

	}
The example usage of the new @Validated annotation is shown in the following example:

	@Controller
	public class MyController {

		@RequestMapping(value = "/user/default", method = RequestMethod.GET)
		public String createDefaultUser(@Validated({ Default.class }) User user, BindingResult result) {
			if(result.hasErrors()) {
				// Validation on 'name'
			}
			return null;
		}

		@RequestMapping(value = "/user/simple", method = RequestMethod.GET)
		public String createSimpleUser(@Validated({ Simple.class }) User user, BindingResult result) {
			if(result.hasErrors()) {
				// Validation on 'licenceType' and 'address'
			}
			return null;
		}

		@RequestMapping(value = "/user/extended", method = RequestMethod.GET)
		public String createExtendedUser(@Validated({ Simple.class, Extended.class }) User user, BindingResult result) {
			if(result.hasErrors()) {
				// Validation on 'creditCard' and 'licenceType' and 'address'
			}

			return null;
		}
	}

The support for validation groups as added to Spring 3.1 is really handy. To read more about validation groups download and read the JSR 303 specification.

3. Support @Valid on @RequestBody method arguments

The @RequestMapping handler methods support @RequestBody annotated parameter for accessing the HTTP request body. The conversion is done through the available message converters, including FormHttpMessageConverter (application/x-www-form-urlencoded), MarshallingHttpMessageConverter (application/xml), MappingJacksonHttpMessageConverter (application/json) and others. But the @RequestBody annotated method argument could not be automatically validated. Manual validation was required:
	@Controller
	public class MyController {

		@Autowired
		private Validator validator;

		@RequestMapping(value = "", method = RequestMethod.PUT)
		@ResponseStatus(value = HttpStatus.CREATED)
		@Secured("ROLE_ADMIN")
		@Transactional
		public void save(@RequestBody User user) {
			validate(user);
			dao.save(user);
		}

		private void validate(User user) {
			// perfom validation using injected validator
		}
	}
In Spring 3.1 the @RequestBody method argument can be annotated with @Valid to invoke automatic validation. This makes the code can be simplified:
@Controller
public class MyController {

	@RequestMapping(value = "/user", method = RequestMethod.POST)
	@ResponseStatus(value = HttpStatus.CREATED)
	@Transactional
	public void save(@Valid @RequestBody User user) {
		dao.save(user);
	}

	@ExceptionHandler
	@ResponseStatus(value = HttpStatus.BAD_REQUEST)
	@ResponseBody
	public String handleMethodArgumentNotValidException(
			MethodArgumentNotValidException error) {
		return "Bad request: " + error.getMessage();
	}
}

In the above example, Spring automatically performs the validation and in case of error MethodArgumentNotValidException is thrown. Optional @ExceptionHandler method may be easily created to add custom behavior for handling this type of exception.

4. Supporting PUT request with form encoded data

The limitation of Servlet implementation is that it does not handle the encoded data of the HTTP PUT request properly. Introduction of the new HttpPutFormContentFilter solves that problem. With Spring 3.1 developing a RESTfull or RESTlike API became much simpler. See my previous post to read more about the usage of HttpPutFormContentFilter in a web application.

5. Java based configuration

The xml configuration of a Spring MVC application may be completely replaced by the Java based configuration. The simplest way to configure a web application is to use the @EnableWebMvc annotation:
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = { "com.example" }, excludeFilters = @Filter(type = FilterType.ANNOTATION, value = Configuration.class))
@Import(PersistanceContextConfiguration.class)
public class ServletContextConfiguration extends WebMvcConfigurerAdapter {

	@Bean
	public TilesViewResolver configureTilesViewResolver() {
		return new TilesViewResolver();
	}

	@Bean
	public TilesConfigurer configureTilesConfigurer() {
		TilesConfigurer configurer = new TilesConfigurer();
		configurer.setDefinitions(new String[] { "/WEB-INF/tiles/tiles.xml",
				"/WEB-INF/views/**/views.xml" });
		return configurer;
	}

	@Override
	public void addViewControllers(ViewControllerRegistry registry) {
		registry.addViewController("login");
	}

	@Override
	public void addResourceHandlers(ResourceHandlerRegistry registry) {
		registry.addResourceHandler("/resources/").addResourceLocations(
				"/recourses/**");
	}

	@Override
	public void configureDefaultServletHandling(
			DefaultServletHandlerConfigurer configurer) {
		configurer.enable();
	}
}
Extending from WebMvcConfigurerAdapter is not required, but it allows for the customization of the default Spring MVC configuration. The adapter enables us to register additional components like formatters, converters, custom validators, interceptors etc. This way the custom configuration can be done by Java code only. See my previous post about configuring a Spring MVC application with no xml in a Servlet 3.0 based environment.

Spring MVC 3.1 has a lot to offer

Spring MVC 3.1 brings many enhancements. The features mentioned in this blog post should have a positive impact on the application development with Spring MVC. They are not revolutionary, though. However, when I look at all the Spring features and enhancements shipped within the 3.1 release, I feel that the framework is going in the right direction. The caching abstraction, bean profiles, configuration simplifications and many other core features should allow to develop applications more efficiently.

References:

  • http://blog.springsource.org/2011/12/13/spring-framework-3-1-goes-ga/
  • http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/new-in-3.1.html
  • http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/

Development Manager and Java Developer at Goyello. Open source enthusiast, team leader, teacher, blogger and Twitter user @kolorobot