To summarize the thread: the @Valid annotation can be used to trigger validation of a parameter to a method of an MVC Controller, but the validation is not properly invoked when the @Valid annotation is used along with the @RequestBody annotation. Without the @RequestBody annotation, the Spring DataBinder mechanism – with full @Valid support – is used to unmarshal the input message to the parameter object. With the @RequestBody annotation, the MessageConverter mechanism – without any @Valid support – is used instead of the DataBinder mechanism.

While waiting for Spring to address this gap, several people have developed work-arounds using Spring AOP. I also decided to use this approach. One of my goals in a work-around was to come up with a solution that was very easy to back out when Spring fixes the problem with @RequestBody and @Valid. The AOP-based approach meets this goal, since we can simply remove the aspect when the framework has proper support for this combination of annotations.

There are a few ways to implement an aspect for this, including one posted to the Spring forum thread by user @taku. The implementations are similar but differ in details like how controller methods are intercepted and how validation errors are dealt with.

The aspect my project is using will intercept a call to a method of a Spring-managed bean when the method has the @RequestMapping annotation on it. (Other approaches intercept methods that following certain naming convention or methods of controllers in certain packages.) Each parameter of an intercepted method is inspected, and an injected validator is called for every parameter that has both the @RequestBody and @Valid annotation on it.

If any method parameter fails validation, an HttpMessageConversionException will be thrown. This exception can then be caught and handled by the framework or by @ExceptionHandler methods in a controller. BindException would have been a more natural exception to throw, but it is a checked exception so it cannot be easily thrown from the aspect.

One limitation with this work-around is that it can only apply a single validator to all controllers. If you are using JSR-303 style annotation-based validation exclusively then this is not a problem – you just inject a LocalValidatorFactoryBean into the aspect. If you need to use a mix of annotation-based validation and class-based validation, this becomes a problem.

To get around this limitation and make this AOP-based approach more flexible, I also implemented a meta-validator that finds all Validator classes in the application context and calls the appropriate validator for the type of object being validated. This meta-validator can then be injected into the aspect (and into the DataBinder). All other validators are just declared as beans in the app context.

Here is an example of a Spring XML configuration file using the validator aspect and the meta-validator together:

12345678910111213141516171819202122

<!-- enable Spring AOP support --><aop:aspectj-autoproxyproxy-target-class="true"/><!-- declare the validator aspect and inject the validator into it --><beanid="validatorAspect"class="com.something.RequestBodyValidatorAspect"><propertyname="validator"ref="validator"/></bean><!-- inject the validator into the DataBinder framework --><beanclass="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"><propertyname="webBindingInitializer"><beanclass="org.springframework.web.bind.support.ConfigurableWebBindingInitializer"p:validator-ref="validator"/></property></bean><!-- declare the meta-validator bean --><beanid="validator"class="com.something.TypeMatchingValidator"/><!-- declare all Validator beans, these will be discovered by TypeMatchingValidator --><beanclass="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/><beanclass="com.something.PersonValidator"/><beanclass="com.something.AccountValidator"/>