Bean Validation in Brief
Spring Framework provides support for the Java Bean Validation
Bean Validation provides a common way to check validity by declaring constraints and metadata for Java applications. To use it, you annotate domain model properties with declarative validation constraints, which are then enforced by the runtime. There are built-in constraints, but you can also define your own constraints.
Consider the following example, which shows a simple PersonForm
model with two
properties:
public class PersonForm {
private String name;
private int age;
}
class PersonForm(
private val name: String,
private val age: Int
)
Bean Validation allows you to declare constraints, as shown in the following example:
public class PersonForm {
@NotNull
@Size(max=64)
private String name;
@Min(0)
private int age;
}
class PersonForm(
@get:NotNull @get:Size(max=64)
private val name: String,
@get:Min(0)
private val age: Int
)
The Bean Validation validator then validates instances of this class based on the declared constraints. For general information about this API, see "Bean Validation". See the Hibernate Validator documentation for specific restrictions. To learn how to configure a bean validation provider as a Spring bean, continue reading.
Configuring a Bean Validation Provider
Spring provides full support for the Bean Validation API, including
bootstrapping the Bean provider Validation as a Spring bean. This allows you to implement javax.validation.ValidatorFactory
or javax.validation.Validator
wherever validation is required in your application.
You can use
LocalValidatorFactoryBean
to configure the default validator as a Spring bean, as shown in the
following example:
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
@Configuration
public class AppConfig {
@Bean
public LocalValidatorFactoryBean validator() {
return new LocalValidatorFactoryBean();
}
}
<bean id="validator"
class="org.springframework.validation. beanvalidation.LocalValidatorFactoryBean"/>
The basic configuration in the previous example causes bean validation to be initialized using the default loading mechanism. A Bean Validation provider, such as the Hibernate Validator, must be on the classpath and be detected automatically.
Validator Injection
LocalValidatorFactoryBean
implements as
javax.validation .ValidatorFactory
and javax.validation.Validator
, as well as org.springframework.validation.Validator
from Spring. You can embed a reference to any of these interfaces in beans that should call the validation logic.
You can embed a reference to javax.validation.Validator
if you prefer to work directly with the API
-Bean Validation interface, as shown in the following example:
import javax.validation.Validator;
@Service
public class MyService {
@Autowired
private Validator validator;
}
import javax.validation.Validator;
@Service
class MyService(@Autowired private val validator: Validator)
You can embed a reference to org.springframework.validation.Validator
, if the bean requires the
Spring Validation API, as shown in the following example:
import org.springframework.validation.Validator;
@Service
public class MyService {
@Autowired
private Validator validator;
}
import org.springframework.validation.Validator
@Service
class MyService(@Autowired private val validator : Validator)
Setting up custom constraints
Each bean validation constraint consists of two parts:
The
@Constraint
annotation, which declares the constraint and its custom properties.Implementations of the
javax.validation.ConstraintValidator interface
, which implements the logic behind the constraint.
To associate the declaration with the implementation, each @Constraint
annotation references the
corresponding ConstraintValidator
implementation class. At runtime,
ConstraintValidatorFactory
instantiates an implementation that is referenced if the constraint
annotation occurs in your domain model.
By default, LocalValidatorFactoryBean
configures
SpringConstraintValidatorFactory
, which uses Spring to create ConstraintValidator
instances.
This allows custom ConstraintValidators
to take advantage of dependency injection just like any other
Spring bean.
The following example shows a custom @Constraint
declaration followed by the
associated implementation ConstraintValidator
, which uses Spring for dependency injection:
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention( RetentionPolicy.RUNTIME)
@Constraint(validatedBy=MyConstraintValidator.class)
public @interface MyConstraint {
}
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.FIELD)
@Retention(AnnotationRetention.RUNTIME)
@Constraint(validatedBy = MyConstraintValidator::class)
annotation class MyConstraint
import javax.validation.ConstraintValidator;
public class MyConstraintValidator implements ConstraintValidator {
@Autowired;
private Foo aDependency;
// ...
}
import javax.validation.ConstraintValidator
class MyConstraintValidator(private val aDependency: Foo) : ConstraintValidator {
// ...
}
As follows from the previous example, the ConstraintValidator
implementation may have its own
dependencies, marked with the @Autowired
annotation, just like any other Spring bean.
Spring-managed method validation
You can implement the method validation functionality supported by Bean
Validation 1.1 (and, as a special extension, also Hibernate Validator 4.3), into the Spring context via the
definition of the MethodValidationPostProcessor
:
import org .springframework.validation.beanvalidation.MethodValidationPostProcessor;
@Configuration
public class AppConfig {
@Bean
public MethodValidationPostProcessor validationPostProcessor() {
return new MethodValidationPostProcessor();
}
}
<bean class="org.springframework.validation.beanvalidation.MethodValidationPostProcessor"/>
To implement Spring-managed method validation, all target classes must be annotated with the
@Validated
annotation from Spring, in which can optionally also declare validation groups for use. See
MethodValidationPostProcessor
for more details on configuring using Hibernate
Validator and Bean Validation 1.1 providers.
Method validation uses AOP proxies to bypass target classes, either dynamic proxies from the JDK for methods on interfaces, or proxies from CGLIB. There are certain restrictions when using a proxy. Also, remember that you should always use methods and accessors for proxied classes; direct access to fields will not work.
Additional configuration options
The default LocalValidatorFactoryBean
configuration is sufficient for most cases. There are a number of configuration options for various Bean Validation
constructs, from message interpolation to enabling traversal. See javadoc at LocalValidatorFactoryBean
for more information about these options.
Configuring DataBinder
As of Spring 3, you can configure a DataBinder
instance
using the Validator
. Once configured, you can call Validator
by calling binder.validate()
.
Any Errors
validity checks are automatically added to the BindingResult
binding.
The following example shows how to programmatically use the DataBinder
to call logic validation checks
after binding to the target:
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 the BindingResult, including all validation errors
BindingResult results = binder.getBindingResult();
val target = Foo()
val binder = DataBinder(target)
binder.validator = FooValidator()
// bind to the target object
binder.bind(propertyValues)
// validate the target object
binder.validate()
// get the BindingResult, which includes everything validation errors
val results = binder.bindingResult
You can also configure DataBinder
using multiple instances of Validator
via dataBinder.addValidators
and dataBinder.replaceValidators
. This makes sense when combining globally configured bean validation
with a Validator
from Spring configured locally for a DataBinder instance.
GO TO FULL VERSION