5.7 Spring 3 Validation

Spring 3 introduces several enhancements to its validation support. First, the JSR-303 Bean Validation API is now fully supported. Second, when used programatically, Spring's DataBinder can now validate objects as well as bind to them. Third, Spring MVC now has support for declaratively validating @Controller inputs.

5.7.1 Overview of the JSR-303 Bean Validation API

JSR-303 standardizes validation constraint declaration and metadata for the Java platform. Using this API, you annotate domain model properties with declarative validation constraints and the runtime enforces them. There are a number of built-in constraints you can can take advantage of. You may also define your own custom constraints.

To illustrate, consider a simple Person model with two properties:

public class Person {
    private String name;
    private int age;
}
			

JSR-303 allows you to define declarative validation constraints against such properties:

public class Person {

    @NotNull
    @Max(64)
    private String name;
    
    @Min(0)
    private int age;

}
			

When an instance of this class is validated by a JSR-303 Validator, these constraints will be enforced.

For general information on JSR-303, see the Bean Validation Specification. For information on the specific capabilities of the default reference implementation, see the Hibernate Validator documentation. To learn how to setup a JSR-303 implementation as a Spring bean, keep reading.

5.7.2 Configuring a Bean Validation Implementation

Spring provides full support for the JSR-303 Bean Validation API. This includes convenient support for bootstrapping a JSR-303 implementation as a Spring bean. This allows a javax.validation.Validator to be injected wherever validation is needed in your application.

Use the LocalValidatorFactoryBean to configure a default JSR-303 Validator as a Spring bean:

<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />
			

The basic configuration above will trigger JSR-303 to initialize using its default bootstrap mechanism. A JSR-303 provider, such as Hibernate Validator, is expected to be present in the classpath and will be detected automatically.

5.7.2.1 Injecting a Validator

LocalValidatorFactoryBean implements both javax.validation.Validator and org.springframework.validation.Validator. You may inject a reference to one of these two interfaces into beans that need to invoke validation logic.

Inject a reference to javax.validation.Validator if you prefer to work with the JSR-303 API directly:

import javax.validation.Validator;

@Service
public class MyService {

    @Autowired
    private Validator validator;

}
				

Inject a reference to org.springframework.validation.Validator if your bean requires the Spring Validation API:

import org.springframework.validation.Validator;

@Service
public class MyService {

    @Autowired
    private Validator validator;

}
				

5.7.2.2 Configuring Custom Constraints

Each JSR-303 validation constraint consists of two parts. First, a @Constraint annotation that declares the constraint and its configurable properties. Second, an implementation of the javax.validation.ConstraintValidator interface that implements the constraint's behavior. To associate a declaration with an implementation, each @Constraint annotation references a corresponding ValidationConstraint implementation class. At runtime, a ConstraintValidatorFactory instantiates the referenced implementation when the constraint annotation is encountered in your domain model.

By default, the LocalValidatorFactoryBean configures a SpringConstraintValidatorFactory that uses Spring to create ConstraintValidator instances. This allows your custom ConstraintValidators to benefit from dependency injection like any other Spring bean.

Shown below is an example of a custom @Constraint declaration, followed by an associated ConstraintValidator implementation that uses Spring for dependency injection:

@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy=MyConstraintValidator.class)
public @interface MyConstraint {
}
				
import javax.validation.ConstraintValidator;

public class MyConstraintValidator implements ConstraintValidator {

    @Autowired;
    private Foo aDependency;

    ...
}
				

As you can see, a ConstraintValidator implementation may have its dependencies @Autowired like any other Spring bean.

5.7.2.3 Additional Configuration Options

The default LocalValidatorFactoryBean configuration should prove sufficient for most cases. There are a number of other configuration options for various JSR-303 constructs, from message interpolation to traversal resolution. See the JavaDocs of LocalValidatorFactoryBean more information on these options.

5.7.3 Configuring a DataBinder

Since Spring 3, a DataBinder instance can be configured with a Validator. Once configured, the Validator may be invoked by calling binder.validate(). Any validation Errors are automatically added to the binder's BindingResults.

When working with the DataBinder programatically, this can be used to invoke validation logic after binding to a target object:

Foo target = new Foo();
DataBinder binder = new DataBinder(target);
binder.setValidator(new FooValidator());

// bind to the target object
binder.bind(propertyValues);

// validate the target object
binder.validate();

// get BindingResults that include any validation errors
BindingResults results = binder.getBindingResults();}
			

5.7.4 Spring MVC 3 Validation

Beginning with Spring 3, Spring MVC has the ability to automatically validate @Controller inputs. In previous versions it was up to the developer to manually invoke validation logic.

5.7.4.1 Triggering @Controller Input Validation

To trigger validation of a @Controller input, simply annotate the input argument as @Valid:

@Controller
public class MyController {

    @RequestMapping("/foo", method=RequestMethod.POST)
    public void processFoo(@Valid Foo foo) { ... }

}
				

Spring MVC will validate a @Valid object after binding so-long as an appropriate Validator has been configured.

[Note]Note

The @Valid annotation is part of the standard JSR-303 Bean Validation API, and is not a Spring-specific construct.

5.7.4.2 Configuring a Validator for use by Spring MVC

The Validator instance invoked when a @Valid method argument is encountered may be configured in two ways. First, you may call binder.setValidator(Validator) within a @Controller's @InitBinder callback. This allows you to configure a Validator instance per @Controller class:

@Controller
public class MyController {

    @InitBinder
    protected void initBinder(WebDataBinder binder) {
        binder.setValidator(new FooValidator());
    }
    
    @RequestMapping("/foo", method=RequestMethod.POST)
    public void processFoo(@Valid Foo foo) { ... }
	
}
				

Second, you may call setValidator(Validator) on the global WebBindingInitializer. This allows you to configure a Validator instance across all @Controllers:

<!-- Invokes Spring MVC @Controller methods -->
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
    <property name="webBindingInitializer">
        <!-- Configures Spring MVC DataBinder instances -->
        <bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
            <property name="validator" ref="validator" />
        </bean>
    </property>
</bean>
				

5.7.4.3 Configuring a JSR-303 Validator for use by Spring MVC

With JSR-303, the default javax.validation.Validator implementation is generic. A single instance typically coordinates the validation of all application objects that declare validation constraints. To configure such a general purpose Validator for use by Spring MVC, simply inject a LocalValidatorFactoryBean reference into the WebBindingInitializer.

A full configuration example showing injection of a JSR-303 backed Validator into Spring MVC is shown below:

<!-- Invokes Spring MVC @Controller methods -->
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
    <property name="webBindingInitializer">
        <!-- Configures Spring MVC DataBinder instances -->
        <bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
            <property name="validator" ref="validator" />
        </bean>
    </property>
</bean>

<!-- Creates the JSR-303 Validator -->
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />
				

With this configuration, anytime a @Valid @Controller input is encountered, it will be validated by the JSR-303 provider. JSR-303, in turn, will enforce any constraints declared against the input. Any ConstaintViolations will automatically be exposed as BindingResults renderable by standard Spring MVC form tags.