瘦瘦的八宝粥 · Spring应用程序属性忽略字符串中的斜杠_ ...· 昨天 · |
果断的火柴 · 用到的java | Morning~Sun.· 昨天 · |
温柔的红薯 · CAS Authentication :: ...· 2 天前 · |
爱运动的热带鱼 · Caused by: ...· 2 天前 · |
温暖的海龟 · 达梦spring-data-jdbc - ...· 4 天前 · |
苦恼的登山鞋 · Spring boot 2 ...· 2 月前 · |
彷徨的熊猫 · 云海历险 - 免费在线观看 - 蜂次元· 4 月前 · |
酷酷的水煮鱼 · Installing PowerShell ...· 11 月前 · |
刚分手的哑铃 · 创建面向多目标框架的.NET项目· 1 年前 · |
冷冷的酱肘子 · 如何评价梦工厂动画《坏蛋联盟》(The ...· 1 年前 · |
爽快的红烧肉
6 月前 |
constraint-mappings
ValidatorFactory
and
Validator
ValidatorFactory
BeanDescriptor
PropertyDescriptor
MethodDescriptor
and
ConstructorDescriptor
ElementDescriptor
GroupConversionDescriptor
ConstraintDescriptor
ParameterMessageInterpolator
ResourceBundleLocator
ParameterNameProvider
Validating data is a common task that occurs throughout all application layers, from the presentation to the persistence layer. Often the same validation logic is implemented in each layer which is time consuming and error-prone. To avoid duplication of these validations, developers often bundle validation logic directly into the domain model, cluttering domain classes with validation code which is really metadata about the class itself.
JSR 349 - Bean Validation 1.1 - defines a metadata model and API for entity and method validation. The default metadata source are annotations, with the ability to override and extend the meta-data through the use of XML. The API is not tied to a specific application tier nor programming model. It is specifically not tied to either web or persistence tier, and is available for both server-side application programming, as well as rich client Swing application developers.
Hibernate Validator is the reference implementation of this JSR 349. The implementation itself as well as the Bean Validation API and TCK are all provided and distributed under the Apache Software License 2.0 .
This chapter will show you how to get started with Hibernate Validator, the reference implementation (RI) of Bean Validation. For the following quick-start you need:
In order to use Hibernate Validator within a Maven project, simply add the following dependency to your pom.xml :
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.4.1.Final</version>
</dependency>
This transitively pulls in the dependency to the Bean Validation API
(
javax.validation:validation-api:1.1.0.Final
).
Hibernate Validator requires an implementation of the Unified Expression Language ( JSR 341 ) for evaluating dynamic expressions in constraint violation messages (see Default message interpolation ). When your application runs in a Java EE container such as JBoss AS, an EL implementation is already provided by the container. In a Java SE environment, however, you have to add an implementation as dependency to your POM file. For instance you can add the following two dependencies to use the JSR 341 reference implementation :
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.el</artifactId>
<version>3.0.1-b08</version>
</dependency>
For environments where one cannot provide a EL implementation Hibernate Validator is offering a
ParameterMessageInterpolator
. However, the use of this interpolator
is not Bean Validation specification compliant.
Bean Validation defines integration points with CDI (Contexts and Dependency Injection for Java TM EE, JSR 346 ). If your application runs in an environment which does not provide this integration out of the box, you may use the Hibernate Validator CDI portable extension by adding the following Maven dependency to your POM:
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator-cdi</artifactId>
<version>5.4.1.Final</version>
</dependency>
Note that adding this dependency is usually not required for applications running on a Java EE application server. You can learn more about the integration of Bean Validation and CDI in CDI .
Hibernate Validator supports running with a security manager being enabled. To do so, you must assign several permissions to the Hibernate Validator and the Bean Validation API code bases. The following shows how to do this via a policy file as processed by the Java default policy implementation:
grant codeBase "file:path/to/hibernate-validator-5.4.1.Final.jar" {
permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
permission java.lang.RuntimePermission "accessDeclaredMembers";
permission java.lang.RuntimePermission "setContextClassLoader";
// Only needed when working with XML descriptors (validation.xml or XML constraint mappings)
permission java.util.PropertyPermission "mapAnyUriToUri", "read";
grant codeBase "file:path/to/validation-api-1.1.0.Final.jar" {
permission java.io.FilePermission "path/to/hibernate-validator-5.4.1.Final.jar", "read";
All API invocations requiring special permissions are done via privileged actions.
This means only Hibernate Validator and the Bean Validation API themselves need the listed permissions.
You don’t need to assign any permissions to other code bases calling Hibernate Validator.
1.1.4. Updating Hibernate Validator in WildFly
The WildFly application server
contains Hibernate Validator out of the box.
In order to update the server modules for Bean Validation API and
Hibernate Validator to the latest and greatest, the patch mechanism of
WildFly can be used.
You can download the patch file from SourceForge or from Maven Central using the following dependency:
Example 5. Maven dependency for WildFly 10.1.0.Final patch file
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator-modules</artifactId>
<version>5.4.1.Final</version>
<classifier>wildfly-10.1.0.Final-patch</classifier>
<type>zip</type>
</dependency>
In case you want to undo the patch and go back to the version of
Hibernate Validator originally coming with the server, run the following
command:
Example 7. Rolling back the WildFly patch
$JBOSS_HOME/bin/jboss-cli.sh patch rollback --reset-configuration=true
1.2. Applying constraints
Lets dive directly into an example to see how to apply constraints.
Example 8. Class Car annotated with constraints
package org.hibernate.validator.referenceguide.chapter01;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
public class Car {
@NotNull
private String manufacturer;
@NotNull
@Size(min = 2, max = 14)
private String licensePlate;
@Min(2)
private int seatCount;
public Car(String manufacturer, String licencePlate, int seatCount) {
this.manufacturer = manufacturer;
this.licensePlate = licencePlate;
this.seatCount = seatCount;
//getters and setters ...
The @NotNull
, @Size
and @Min
annotations are used to declare the constraints which should be applied
to the fields of a Car instance:
You can find the complete source code of all examples used in this reference guide in the Hibernate
Validator
source repository
on GitHub.
1.3. Validating constraints
To perform a validation of these constraints, you use a Validator
instance. Let’s have a look at a
unit test for Car
:
Example 9. Class CarTest showing validation examples
package org.hibernate.validator.referenceguide.chapter01;
import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class CarTest {
private static Validator validator;
@BeforeClass
public static void setUpValidator() {
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
validator = factory.getValidator();
@Test
public void manufacturerIsNull() {
Car car = new Car( null, "DD-AB-123", 4 );
Set<ConstraintViolation<Car>> constraintViolations =
validator.validate( car );
assertEquals( 1, constraintViolations.size() );
assertEquals( "may not be null", constraintViolations.iterator().next().getMessage() );
@Test
public void licensePlateTooShort() {
Car car = new Car( "Morris", "D", 4 );
Set<ConstraintViolation<Car>> constraintViolations =
validator.validate( car );
assertEquals( 1, constraintViolations.size() );
assertEquals(
"size must be between 2 and 14",
constraintViolations.iterator().next().getMessage()
@Test
public void seatCountTooLow() {
Car car = new Car( "Morris", "DD-AB-123", 1 );
Set<ConstraintViolation<Car>> constraintViolations =
validator.validate( car );
assertEquals( 1, constraintViolations.size() );
assertEquals(
"must be greater than or equal to 2",
constraintViolations.iterator().next().getMessage()
@Test
public void carIsValid() {
Car car = new Car( "Morris", "DD-AB-123", 2 );
Set<ConstraintViolation<Car>> constraintViolations =
validator.validate( car );
assertEquals( 0, constraintViolations.size() );
In the setUp()
method a Validator
object is retrieved from the ValidatorFactory
. A Validator
instance is thread-safe and may be reused multiple times. It thus can safely be stored in a static
field and be used in the test methods to validate the different Car
instances.
The validate()
method returns a set of ConstraintViolation
instances, which you can iterate over in
order to see which validation errors occurred. The first three test methods show some expected
constraint violations:
If the object validates successfully, validate()
returns an empty set as you can see in carIsValid()
.
Note that only classes from the package javax.validation
are used. These are provided from the Bean
Validation API. No classes from Hibernate Validator are directly referenced, resulting in portable
code.
1.4. Java 8 support
Java 8 introduces several enhancements which are valuable from a Hibernate Validator point of view.
This section briefly introduces the Hibernate Validator features based on Java 8.
They are only available in Hibernate Validator 5.2 and later.
1.4.1. Type arguments constraints
In Java 8 it is possible to use annotations in any location a type is used. This includes type
arguments. Hibernate Validator supports the validation of constraints defined on type arguments
of collections, maps, and custom parameterized types. The Type argument constraints chapter
provides further information on how to apply and use type argument constraints.
1.4.2. Actual parameter names
The Java 8 Reflection API can now retrieve the actual parameter names of a method or constructor.
Hibernate Validator uses this ability to report the actual parameter names instead of arg0
,
arg1
, etc. The ParameterNameProvider
chapter explains how to use the new reflection
based parameter name provider.
1.4.3. New date/time API
Java 8 introduces a new date/time API. Hibernate Validator provides full support for the new API
where @Future
and @Past
constraints can be applied on the new types.
The complete list of types supported for @Future
and @Past
can be found in Bean Validation constraints.
1.4.4. Optional type
Hibernate Validator provides also support for Java 8 Optional
type, by unwrapping the Optional
instance and validating the internal value. Optional unwrapper provides examples and a
further discussion.
1.5. Where to go next?
That concludes the 5 minute tour through the world of Hibernate Validator and Bean Validation.
Continue exploring the code examples or look at further examples referenced in
Further reading.
To learn more about the validation of beans and properties, just continue reading
Declaring and validating bean constraints. If you are interested in using Bean Validation for the validation of
method pre- and postcondition refer to Declaring and validating method constraints. In case your application has
specific validation requirements have a look at Creating custom constraints.
In this chapter you will learn how to declare (see Declaring bean constraints) and
validate (see Validating bean constraints) bean constraints.
Built-in constraints provides an overview of all built-in constraints coming with
Hibernate Validator.
If you are interested in applying constraints to method parameters and return values, refer to
Declaring and validating method constraints.
2.1. Declaring bean constraints
Constraints in Bean Validation are expressed via Java annotations. In this section you will learn
how to enhance an object model with these annotations. There are the following three types of bean
constraints:
Not all constraints can be placed on all of these levels. In fact, none of the default constraints
defined by Bean Validation can be placed at class level. The java.lang.annotation.Target
annotation
in the constraint annotation itself determines on which elements a constraint can be placed. See
Creating custom constraints for more information.
2.1.1. Field-level constraints
Constraints can be expressed by annotating a field of a class. Field-level constraints shows a field
level configuration example:
Example 10. Field-level constraints
package org.hibernate.validator.referenceguide.chapter02.fieldlevel;
public class Car {
@NotNull
private String manufacturer;
@AssertTrue
private boolean isRegistered;
public Car(String manufacturer, boolean isRegistered) {
this.manufacturer = manufacturer;
this.isRegistered = isRegistered;
//getters and setters...
When using field-level constraints field access strategy is used to access the value to be
validated. This means the validation engine directly accesses the instance variable and does not
invoke the property accessor method even if such an accessor exists.
Constraints can be applied to fields of any access type (public, private etc.). Constraints on
static fields are not supported, though.
When validating byte code enhanced objects property level constraints should be used, because the
byte code enhancing library won’t be able to determine a field access via reflection.
If your model class adheres to the
JavaBeans standard, it
is also possible to annotate the properties of a bean class instead of its fields.
Property-level constraints uses the same entity as in Field-level constraints, however, property level
constraints are used.
Example 11. Property-level constraints
package org.hibernate.validator.referenceguide.chapter02.propertylevel;
public class Car {
private String manufacturer;
private boolean isRegistered;
public Car(String manufacturer, boolean isRegistered) {
this.manufacturer = manufacturer;
this.isRegistered = isRegistered;
@NotNull
public String getManufacturer() {
return manufacturer;
public void setManufacturer(String manufacturer) {
this.manufacturer = manufacturer;
@AssertTrue
public boolean isRegistered() {
return isRegistered;
public void setRegistered(boolean isRegistered) {
this.isRegistered = isRegistered;
The property’s getter method has to be annotated, not its setter. That way also read-only properties
can be constrained which have no setter method.
When using property level constraints property access strategy is used to access the value to be
validated, i.e. the validation engine accesses the state via the property accessor method.
It is recommended to stick either to field or property annotations within one class. It is not
recommended to annotate a field and the accompanying getter method as this would cause the field
to be validated twice.
2.1.3. Type argument constraints
Starting from Java 8, it is possible to specify constraints directly on the type argument of a
parameterized type. However, this requires that ElementType.TYPE_USE
is specified via @Target
in the constraint definition. To maintain backwards compatibility, built-in Bean Validation as well as
Hibernate Validator specific constraints do not yet specify ElementType.TYPE_USE
. To make use of
type argument constraints, custom constraints must be used (see Creating custom constraints).
Hibernate Validator validates type arguments constraints specified on collections, map values,
java.util.Optional
, and custom parameterized types.
With Iterable
When applying constraints on an Iterable
type argument, Hibernate Validator will validate each
element. Type argument constraint on List
shows an example of a
List
with a type argument constraint.
In this example, @ValidPart
is a custom constraint allowed to be used in the TYPE_USE
context.
Example 12. Type argument constraint on List
package org.hibernate.validator.referenceguide.chapter02.typeargument.list;
public class Car {
@Valid
private List<@ValidPart String> parts = new ArrayList<>();
public void addPart(String part) {
parts.add( part );
//...
car.addPart( null );
Set<ConstraintViolation<Car>> constraintViolations = validator.validate( car );
assertEquals( 1, constraintViolations.size() );
assertEquals(
"'null' is not a valid car part.",
constraintViolations.iterator().next().getMessage()
assertEquals( "parts[1].<collection element>",
constraintViolations.iterator().next().getPropertyPath().toString() );
With Map
Type argument constraints are also validated for map values. Constraints on the key are ignored.
Type argument constraint on maps shows an example of a Map
value with a type
argument constraint.
Example 13. Type argument constraint on maps
package org.hibernate.validator.referenceguide.chapter02.typeargument.map;
public class Car {
public enum FuelConsumption {
CITY,
HIGHWAY
@Valid
private EnumMap<FuelConsumption, @MaxAllowedFuelConsumption Integer> fuelConsumption = new EnumMap<>( FuelConsumption.class );
public void setFuelConsumption(FuelConsumption consumption, int value) {
fuelConsumption.put( consumption, value );
//...
Car car = new Car();
car.setFuelConsumption( Car.FuelConsumption.HIGHWAY, 20 );
Set<ConstraintViolation<Car>> constraintViolations = validator.validate( car );
assertEquals( 1, constraintViolations.size() );
assertEquals( "20 is outside the max fuel consumption.", constraintViolations.iterator().next().getMessage() );
With java.util.Optional
When applying a constraint on the type argument of Optional
, Hibernate Validator will automatically
unwrap the type and validate the internal value. Type argument constraint on Optional shows
an example of an Optional
with a type argument constraint.
Example 14. Type argument constraint on Optional
package org.hibernate.validator.referenceguide.chapter02.typeargument.optional;
public class Car {
private Optional<@MinTowingCapacity(1000) Integer> towingCapacity = Optional.empty();
public void setTowingCapacity(Integer alias) {
towingCapacity = Optional.of( alias );
//...
car.setTowingCapacity( 100 );
Set<ConstraintViolation<Car>> constraintViolations = validator.validate( car );
assertEquals( 1, constraintViolations.size() );
assertEquals( "Not enough towing capacity.",
constraintViolations.iterator().next().getMessage() );
assertEquals( "towingCapacity",
constraintViolations.iterator().next().getPropertyPath().toString() );
With custom parameterized types
Type arguments constraints can with two restrictions also be used with custom types. First, a
ValidatedValueUnwrapper
must be registered for the custom type allowing to retrieve
the value to validate (see Unwrapping values). Second, only types with one type arguments
are supported. Parameterized types with two or more type arguments are not checked for type argument
constraints. This limitation might change in future versions.
Type argument constraint on custom parameterized type shows an example of a custom
parameterized type with a type argument constraint.
Example 15. Type argument constraint on custom parameterized type
package org.hibernate.validator.referenceguide.chapter02.typeargument.custom;
public class Car {
private GearBox<@MinTorque(100) Gear> gearBox;
public void setGearBox(GearBox<Gear> gearBox) {
this.gearBox = gearBox;
//...
package org.hibernate.validator.referenceguide.chapter02.typeargument.custom;
public class GearBox<T extends Gear> {
private final T gear;
public GearBox(T gear) {
this.gear = gear;
public Gear getGear() {
return this.gear;
package org.hibernate.validator.referenceguide.chapter02.typeargument.custom;
public class Gear {
private final Integer torque;
public Gear(Integer torque) {
this.torque = torque;
public Integer getTorque() {
return torque;
public static class AcmeGear extends Gear {
public AcmeGear() {
super( 100 );
package org.hibernate.validator.referenceguide.chapter02.typeargument.custom;
public class GearBoxUnwrapper extends ValidatedValueUnwrapper<GearBox> {
@Override
public Object handleValidatedValue(GearBox gearBox) {
return gearBox == null ? null : gearBox.getGear();
@Override
public Type getValidatedValueType(Type valueType) {
return Gear.class;
Car car = new Car();
car.setGearBox( new GearBox<>( new Gear.AcmeGear() ) );
Set<ConstraintViolation<Car>> constraintViolations = validator.validate( car );
assertEquals( 1, constraintViolations.size() );
assertEquals( "Gear is not providing enough torque.", constraintViolations.iterator().next().getMessage() );
assertEquals( "gearBox", constraintViolations.iterator().next().getPropertyPath().toString() );
2.1.4. Class-level constraints
Last but not least, a constraint can also be placed on the class level. In this case not a single
property is subject of the validation but the complete object. Class-level constraints are useful if
the validation depends on a correlation between several properties of an object.
The Car class in Class-level constraint has the two attributes seatCount
and passengers
and it
should be ensured that the list of passengers has not more entries than seats are available. For
that purpose the @ValidPassengerCount
constraint is added on the class level. The validator of that
constraint has access to the complete Car
object, allowing to compare the numbers of seats and
passengers.
Refer to Class-level constraints to learn in detail how to implement this custom
constraint.
Example 16. Class-level constraint
package org.hibernate.validator.referenceguide.chapter02.classlevel;
@ValidPassengerCount
public class Car {
private int seatCount;
private List<Person> passengers;
//...
2.1.5. Constraint inheritance
When a class implements an interface or extends another class, all constraint annotations declared
on the super-type apply in the same manner as the constraints specified on the class itself. To make
things clearer let’s have a look at the following example:
Example 17. Constraint inheritance
package org.hibernate.validator.referenceguide.chapter02.inheritance;
public class Car {
private String manufacturer;
@NotNull
public String getManufacturer() {
return manufacturer;
//...
package org.hibernate.validator.referenceguide.chapter02.inheritance;
public class RentalCar extends Car {
private String rentalStation;
@NotNull
public String getRentalStation() {
return rentalStation;
//...
Here the class RentalCar
is a subclass of Car
and adds the property rentalStation
. If an instance of
RentalCar
is validated, not only the @NotNull
constraint on rentalStation
is evaluated, but also the
constraint on manufacturer
from the parent class.
The same would be true, if Car
was not a superclass but an interface implemented by RentalCar
.
Constraint annotations are aggregated if methods are overridden. So if RentalCar
overrode the
getManufacturer()
method from Car
, any constraints annotated at the overriding method would be
evaluated in addition to the @NotNull
constraint from the superclass.
2.1.6. Object graphs
The Bean Validation API does not only allow to validate single class instances but also complete
object graphs (cascaded validation). To do so, just annotate a field or property representing a
reference to another object with @Valid
as demonstrated in Cascaded validation.
Example 18. Cascaded validation
package org.hibernate.validator.referenceguide.chapter02.objectgraph;
public class Car {
@NotNull
@Valid
private Person driver;
//...
package org.hibernate.validator.referenceguide.chapter02.objectgraph;
public class Person {
@NotNull
private String name;
//...
If an instance of Car
is validated, the referenced Person
object will be validated as well, as the
driver
field is annotated with @Valid
. Therefore the validation of a Car
will fail if the name
field
of the referenced Person
instance is null
.
The validation of object graphs is recursive, i.e. if a reference marked for cascaded validation
points to an object which itself has properties annotated with @Valid
, these references will be
followed up by the validation engine as well. The validation engine will ensure that no infinite
loops occur during cascaded validation, for example if two objects hold references to each other.
Note that null
values are getting ignored during cascaded validation.
Object graph validation also works for collection-typed fields. That means any attributes that
can be annotated with @Valid
, which will cause each contained element to be validated, when the
parent object is validated.
Example 19. Cascaded validation of a collection
package org.hibernate.validator.referenceguide.chapter02.objectgraph.list;
public class Car {
@NotNull
@Valid
private List<Person> passengers = new ArrayList<Person>();
//...
So when validating an instance of the Car
class shown in Cascaded validation of a collection, a
ConstraintViolation
will be created, if any of the Person
objects contained in the passengers list
has a null
name.
2.2. Validating bean constraints
The Validator
interface is the most important object in Bean Validation. The next section shows how
to obtain an Validator
instance. Afterwards you’ll learn how to use the different methods of the
Validator
interface.
2.2.1. Obtaining a Validator
instance
The first step towards validating an entity instance is to get hold of a Validator
instance. The
road to this instance leads via the Validation
class and a ValidatorFactory
. The easiest way is to
use the static method Validation#buildDefaultValidatorFactory()
:
Example 20. Validation#buildDefaultValidatorFactory()
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
validator = factory.getValidator();
This bootstraps a validator in the default configuration. Refer to Bootstrapping to
learn more about the different bootstrapping methods and how to obtain a specifically configured
Validator
instance.
2.2.2. Validator methods
The Validator
interface contains three methods that can be used to either validate entire entities
or just single properties of the entity.
All three methods return a Set<ConstraintViolation>
. The set is empty, if the validation succeeds.
Otherwise a ConstraintViolation
instance is added for each violated constraint.
All the validation methods have a var-args parameter which can be used to specify, which validation
groups shall be considered when performing the validation. If the parameter is not specified the
default validation group (javax.validation.groups.Default
) is used. The topic of validation groups
is discussed in detail in Grouping constraints.
Validator#validate()
Use the validate()
method to perform validation of all constraints of a given bean.
Using Validator#validate()
shows the validation of an instance of the Car
class from
Property-level constraints which fails to satisfy the @NotNull
constraint on the manufacturer
property. The validation call therefore returns one ConstraintViolation
object.
Example 21. Using Validator#validate()
Car car = new Car( null, true );
Set<ConstraintViolation<Car>> constraintViolations = validator.validate( car );
assertEquals( 1, constraintViolations.size() );
assertEquals( "may not be null", constraintViolations.iterator().next().getMessage() );
Validator#validateProperty()
With help of the validateProperty()
you can validate a single named property of a given object. The
property name is the JavaBeans property name.
Example 22. Using Validator#validateProperty()
Car car = new Car( null, true );
Set<ConstraintViolation<Car>> constraintViolations = validator.validateProperty(
car,
"manufacturer"
assertEquals( 1, constraintViolations.size() );
assertEquals( "may not be null", constraintViolations.iterator().next().getMessage() );
Validator#validateValue()
By using the validateValue()
method you can check whether a single property of a given class can be
validated successfully, if the property had the specified value:
Example 23. Using Validator#validateValue()
Set<ConstraintViolation<Car>> constraintViolations = validator.validateValue(
Car.class,
"manufacturer",
assertEquals( 1, constraintViolations.size() );
assertEquals( "may not be null", constraintViolations.iterator().next().getMessage() );
Validator#validateProperty()
is for example used in the integration of Bean Validation into JSF 2
(see JSF & Seam) to perform a validation of the values entered into a form
before they are propagated to the model.
2.2.3. ConstraintViolation
methods
Now it is time to have a closer look at what a ConstraintViolation
is.
Using the different methods of ConstraintViolation
a lot of useful information about the cause of the validation failure can be determined.
The following gives an overview of these methods.
The values under "Example" column refer to Using Validator#validate()
.
getMessage()
The interpolated error message
Example
"may not be null"
If a bean constraint, the bean instance the constraint is
applied on; if a property constraint, the bean instance hosting
the property the constraint is applied on
Example
2.3. Built-in constraints
Hibernate Validator comprises a basic set of commonly used constraints. These are foremost the
constraints defined by the Bean Validation specification (see Bean Validation constraints).
Additionally, Hibernate Validator provides useful custom constraints (see
Additional constraints).
2.3.1. Bean Validation constraints
Below you can find a list of all constraints specified in the Bean
Validation API.
All these constraints apply to the field/property level, there are no
class-level constraints defined in the Bean Validation specification.
If you are using the Hibernate object-relational mapper, some of the
constraints are taken into account when creating the DDL for your model
(see "Hibernate metadata impact").
Hibernate Validator allows some constraints to be applied to more data types than required by the
Bean Validation specification (e.g. @Max
can be applied to strings). Relying on this feature can
impact portability of your application between Bean Validation providers.
@DecimalMax(value=, inclusive=)
Checks whether the annotated value is less than the specified maximum, when inclusive
=false.
Otherwise whether the value is less than or equal to the specified
maximum. The parameter value is the string representation of the max
value according to the BigDecimal
string representation.
Supported data types
BigDecimal
, BigInteger
, CharSequence
, byte
, short
, int
, long
and the respective wrappers of the primitive types; additionally supported by HV: any sub-type of Number
and javax.money.MonetaryAmount
(if the JSR 354 API and an implementation is on the class path)
Hibernate metadata impact
@DecimalMin(value=, inclusive=)
Checks whether the annotated value is larger than the specified minimum, when inclusive
=false.
Otherwise whether the value is larger than or equal to the specified
minimum. The parameter value is the string representation of the min
value according to the BigDecimal
string representation.
Supported data types
BigDecimal
, BigInteger
, CharSequence
, byte
, short
, int
, long
and the respective wrappers of the primitive types; additionally supported by HV: any sub-type of Number
and javax.money.MonetaryAmount
Hibernate metadata impact
@Digits(integer=, fraction=)
Checks whether the annotated value is a number having up to integer
digits and fraction
fractional digits
Supported data types
BigDecimal, BigInteger
, CharSequence
, byte
, short
, int
, long
and the respective wrappers of the primitive types; additionally supported by HV: any sub-type of Number
Hibernate metadata impact
Defines column precision and scale
Supported data types
java.util.Date
, java.util.Calendar
, java.time.chrono.ChronoZonedDateTime
, java.time.Instant
, java.time.OffsetDateTime
; additionally supported by HV, if the Joda Time date/time API is on the classpath: any implementations of ReadablePartial
and ReadableInstant
Hibernate metadata impact
@Max(value=)
Checks whether the annotated value is less than or equal to the specified maximum
Supported data types
BigDecimal
, BigInteger
, byte
, short
, int
, long
and the respective wrappers of the primitive types; additionally supported by HV: any sub-type of CharSequence
(the numeric value represented by the character sequence is evaluated), any sub-type of Number
and javax.money.MonetaryAmount
Hibernate metadata impact
Adds a check constraint on the column
@Min(value=)
Checks whether the annotated value is higher than or equal to the specified minimum
Supported data types
BigDecimal
, BigInteger
, byte
, short
, int
, long
and the respective wrappers of the primitive types; additionally supported by HV: any sub-type of CharSequence
(the numeric value represented by the character sequence is evaluated), any sub-type of Number
and javax.money.MonetaryAmount
Hibernate metadata impact
Adds a check constraint on the column
Supported data types
java.util.Date
, java.util.Calendar
, java.time.chrono.ChronoZonedDateTime
, java.time.Instant
, java.time.OffsetDateTime
; Additionally supported by HV, if the Joda Time date/time API is on the classpath: any implementations of ReadablePartial
and ReadableInstant
Hibernate metadata impact
@Pattern(regex=, flags=)
Checks if the annotated string matches the regular expression regex
considering the given flag match
Supported data types
CharSequence
Hibernate metadata impact
@Size(min=, max=)
Checks if the annotated element’s size is between min
and max
(inclusive)
Supported data types
CharSequence
, Collection
, Map
and arrays
Hibernate metadata impact
Column length will be set to max
Performs validation recursively on the associated object. If the
object is a collection or an array, the elements are validated
recursively. If the object is a map, the value elements are validated
recursively.
Supported data types
Any non-primitive type
Hibernate metadata impact
2.3.2. Additional constraints
In addition to the constraints defined by the Bean Validation API
Hibernate Validator provides several useful custom constraints which are
listed below.
With one exception also these constraints apply to the field/property
level, only @ScriptAssert
is a class-level constraint.
@CreditCardNumber(ignoreNonDigitCharacters=)
Checks that the annotated character sequence passes the Luhn checksum
test. Note, this validation aims to check for user mistakes, not credit
card validity! See also Anatomy of Credit Card Numbers. ignoreNonDigitCharacters
allows to ignore non digit characters. The default is false
.
Supported data types
CharSequence
Hibernate metadata impact
@Currency(value=)
Checks that the currency unit of the annotated javax.money.MonetaryAmount
is part of the specified currency units.
Supported data types
any sub-type of javax.money.MonetaryAmount
(if the JSR 354 API and an implementation is on the class path)
Hibernate metadata impact
Checks that the annotated character sequence is a valid EAN barcode. type determines the type of barcode. The default is EAN-13.
Supported data types
CharSequence
Hibernate metadata impact
@Email
Checks whether the specified character sequence is a valid email address. The optional parameters regexp
and flags
allow to specify an additional regular expression (including regular expression flags) which the email must match.
Supported data types
CharSequence
Hibernate metadata impact
@Length(min=, max=)
Validates that the annotated character sequence is between min
and max
included
Supported data types
CharSequence
Hibernate metadata impact
Column length will be set to max
@LuhnCheck(startIndex= , endIndex=, checkDigitIndex=, ignoreNonDigitCharacters=)
Checks that the digits within the annotated character sequence pass the Luhn checksum algorithm (see also Luhn algorithm). startIndex
and endIndex
allow to only run the algorithm on the specified sub-string. checkDigitIndex
allows to use an arbitrary digit within the character sequence as the
check digit. If not specified it is assumed that the check digit is part
of the specified range. Last but not least, ignoreNonDigitCharacters
allows to ignore non digit characters.
Supported data types
CharSequence
Hibernate metadata impact
@Mod10Check(multiplier=, weight=, startIndex=, endIndex=, checkDigitIndex=, ignoreNonDigitCharacters=)
Checks that the digits within the annotated character sequence pass the generic mod 10 checksum algorithm. multiplier
determines the multiplier for odd numbers (defaults to 3), weight
the weight for even numbers (defaults to 1). startIndex
and endIndex
allow to only run the algorithm on the specified sub-string. checkDigitIndex
allows to use an arbitrary digit within the character sequence as the
check digit. If not specified it is assumed that the check digit is part
of the specified range. Last but not least, ignoreNonDigitCharacters
allows to ignore non digit characters.
Supported data types
CharSequence
Hibernate metadata impact
@Mod11Check(threshold=, startIndex=, endIndex=, checkDigitIndex=, ignoreNonDigitCharacters=, treatCheck10As=, treatCheck11As=)
Checks that the digits within the annotated character sequence pass the mod 11 checksum algorithm. threshold
specifies the threshold for the mod11 multiplier growth; if no value is specified the multiplier will grow indefinitely. treatCheck10As
and treatCheck11As
specify the check digits to be used when the mod 11 checksum equals 10 or 11, respectively. Default to X and 0, respectively. startIndex
, endIndex
checkDigitIndex
and ignoreNonDigitCharacters
carry the same semantics as in @Mod10Check
.
Supported data types
CharSequence
Hibernate metadata impact
@NotBlank
Checks that the annotated character sequence is not null and the trimmed length is greater than 0. The difference to @NotEmpty
is that this constraint can only be applied on strings and that trailing white-spaces are ignored.
Supported data types
CharSequence
Hibernate metadata impact
@Range(min=, max=)
Checks whether the annotated value lies between (inclusive) the specified minimum and maximum
Supported data types
BigDecimal
, BigInteger
, CharSequence
, byte
, short
, int
, long
and the respective wrappers of the primitive types
Hibernate metadata impact
@SafeHtml(whitelistType= , additionalTags=, additionalTagsWithAttributes=)
Checks whether the annotated value contains potentially malicious fragments such as <script/>
. In order to use this constraint, the jsoup library must be part of the class path. With the whitelistType
attribute a predefined whitelist type can be chosen which can be refined via additionalTags
or additionalTagsWithAttributes
.
The former allows to add tags without any attributes, whereas the
latter allows to specify tags and optionally allowed attributes using
the annotation @SafeHtml.Tag
.
Supported data types
CharSequence
Hibernate metadata impact
@ScriptAssert(lang=, script=, alias=, reportOn=)
Checks whether the given script can successfully be evaluated against
the annotated element. In order to use this constraint, an
implementation of the Java Scripting API as defined by JSR 223
("Scripting for the JavaTM Platform") must be a part of the
class path. The expressions to be evaluated can be written in any
scripting or expression language, for which a JSR 223 compatible engine
can be found in the class path. Even though this is a class-level
constraint, one can use the reportOn
attribute to report a constraint violation on a specific property rather than the whole object.
Supported data types
Any type
Hibernate metadata impact
@URL(protocol=, host=, port=, regexp=, flags=)
Checks if the annotated character sequence is a valid URL according to RFC2396. If any of the optional parameters protocol
, host
or port
are specified, the corresponding URL fragments must match the specified values. The optional parameters regexp
and flags
allow to specify an additional regular expression (including regular
expression flags) which the URL must match. Per default this constraint
used the java.net.URL
constructor to verify whether a given string represents a valid URL. A regular expression based version is also available - RegexpURLValidator
- which can be configured via XML (see Mapping constraints via constraint-mappings
) or the programmatic API (see Adding constraint definitions programmatically).
Supported data types
CharSequence
Hibernate metadata impact
Country specific constraints
Hibernate Validator offers also some country specific constraints, e.g. for the validation of social
security numbers.
If you have to implement a country specific constraint, consider making it a contribution to
Hibernate Validator!
Checks that the annotated character sequence represents a Brazilian
corporate tax payer registry number (Cadastro de Pessoa Juríeddica)
Supported data types
CharSequence
Hibernate metadata impact
Country
Brazil
Checks that the annotated character sequence represents a Brazilian
individual taxpayer registry number (Cadastro de Pessoa Fídsica)
Supported data types
CharSequence
Hibernate metadata impact
Country
Brazil
@TituloEleitoral
Checks that the annotated character sequence represents a Brazilian voter ID card number (Título Eleitoral)
Supported data types
CharSequence
Hibernate metadata impact
Country
Brazil
Checks that the annotated character sequence represents a Polish VAT identification number (NIP)
Supported data types
CharSequence
Hibernate metadata impact
Country
Poland
@PESEL
Checks that the annotated character sequence represents a Polish national identification number (PESEL)
Supported data types
CharSequence
Hibernate metadata impact
Country
Poland
@REGON
Checks that the annotated character sequence represents a Polish taxpayer identification number (REGON). Can be applied to both 9 and 14 digits versions of REGON
Supported data types
CharSequence
Hibernate metadata impact
Country
Poland
In some cases neither the Bean Validation constraints nor the custom constraints provided by
Hibernate Validator will fulfill your requirements. In this case you can easily write your own
constraint. You can find more information in Creating custom constraints.
As of Bean Validation 1.1, constraints can not only be applied to JavaBeans and their properties,
but also to the parameters and return values of the methods and constructors of any Java type. That
way Bean Validation constraints can be used to specify
the preconditions that must be satisfied by the caller before a method or constructor may be
invoked (by applying constraints to the parameters of an executable)
the postconditions that are guaranteed to the caller after a method or constructor invocation
returns (by applying constraints to the return value of an executable)
For the purpose of this reference guide, the term method constraint refers to both, method and
constructor constraints, if not stated otherwise. Occasionally, the term executable is used when
referring to methods and constructors.
This approach has several advantages over traditional ways of checking the correctness of parameters
and return values:
the checks don’t have to be performed manually (e.g. by throwing IllegalArgumentException
or
similar), resulting in less code to write and maintain
an executable’s pre- and postconditions don’t have to be expressed again in its documentation,
since the constraint annotations will automatically be included in the generated JavaDoc. This
avoids redundancies and reduces the chance of inconsistencies between implementation and
documentation
In order to make annotations show up in the JavaDoc of annotated elements, the annotation types
themselves must be annotated with the meta annotation @Documented. This is the case for all built-in
constraints and is considered a best practice for any custom constraints.
In the remainder of this chapter you will learn how to declare parameter and return value
constraints and how to validate them using the ExecutableValidator
API.
3.1. Declaring method constraints
3.1.1. Parameter constraints
You specify the preconditions of a method or constructor by adding constraint annotations to its
parameters as demonstrated in Declaring method and constructor parameter constraints.
Example 24. Declaring method and constructor parameter constraints
package org.hibernate.validator.referenceguide.chapter03.parameter;
public class RentalStation {
public RentalStation(@NotNull String name) {
//...
public void rentCar(
@NotNull Customer customer,
@NotNull @Future Date startDate,
@Min(1) int durationInDays) {
//...
When invoking the rentCar()
method, the given customer
must not be null
, the rental’s start
date must not be null
as well as be in the future and finally the rental duration must be at least
one day
Note that declaring method or constructor constraints itself does not automatically cause their
validation upon invocation of the executable. Instead, the ExecutableValidator
API (see
Validating method constraints) must be used to perform the validation, which is
often done using a method interception facility such as AOP, proxy objects etc.
Constraints may only be applied to instance methods, i.e. declaring constraints on static methods is
not supported. Depending on the interception facility you use for triggering method validation,
additional restrictions may apply, e.g. with respect to the visibility of methods supported as
target of interception. Refer to the documentation of the interception technology to find out
whether any such limitations exist.
Cross-parameter constraints
Sometimes validation does not only depend on a single parameter but on several or even all
parameters of a method or constructor. This kind of requirement can be fulfilled with help of a
cross-parameter constraint.
Cross-parameter constraints can be considered as the method validation equivalent to class-level
constraints. Both can be used to implement validation requirements which are based on several
elements. While class-level constraints apply to several properties of a bean, cross-parameter
constraints apply to several parameters of an executable.
In contrast to single-parameter constraints, cross-parameter constraints are declared on the method
or constructor as you can see in Declaring a cross-parameter constraint. Here the cross-
parameter constraint @LuggageCountMatchesPassengerCount
declared on the load()
method is used to
ensure that no passenger has more than two pieces of luggage.
Example 25. Declaring a cross-parameter constraint
package org.hibernate.validator.referenceguide.chapter03.crossparameter;
public class Car {
@LuggageCountMatchesPassengerCount(piecesOfLuggagePerPassenger = 2)
public void load(List<Person> passengers, List<PieceOfLuggage> luggage) {
//...
As you will learn in the next section, return value constraints are also declared on the method
level. In order to distinguish cross-parameter constraints from return value constraints, the
constraint target is configured in the ConstraintValidator
implementation using the
@SupportedValidationTarget
annotation. You can find out about the details in
Cross-parameter constraints which shows how to implement your own cross-parameter constraint.
In some cases a constraint can be applied to an executable’s parameters (i.e. it is a cross-
parameter constraint), but also to the return value. One example for this are custom constraints
which allow to specify validation rules using expression or script languages.
Such constraints must define a member validationAppliesTo()
which can be used at declaration time to
specify the constraint target. As shown in Specifying a constraint’s target you apply the
constraint to an executable’s parameters by specifying
validationAppliesTo = ConstraintTarget.PARAMETERS
, while ConstraintTarget.RETURN_VALUE
is used
to apply the constraint to the executable return value.
Example 26. Specifying a constraint’s target
package org.hibernate.validator.referenceguide.chapter03.crossparameter.constrainttarget;
public class Garage {
@ELAssert(expression = "...", validationAppliesTo = ConstraintTarget.PARAMETERS)
public Car buildCar(List<Part> parts) {
//...
return null;
@ELAssert(expression = "...", validationAppliesTo = ConstraintTarget.RETURN_VALUE)
public Car paintCar(int color) {
//...
return null;
Although such a constraint is applicable to the parameters and return value of an executable, the
target can often be inferred automatically. This is the case, if the constraint is declared on
an executable with return value but no parameters (the constraint applies to the return value)
neither a method nor a constructor, but a field, parameter etc. (the constraint applies to the
annotated element)
In these situations you don’t have to specify the constraint target. It is still recommended to do
so if it increases readability of the source code. If the constraint target is not specified in
situations where it can’t be determined automatically, a ConstraintDeclarationException is raised.
3.1.2. Return value constraints
The postconditions of a method or constructor are declared by adding constraint annotations to the
executable as shown in Declaring method and constructor return value constraints.
Example 27. Declaring method and constructor return value constraints
package org.hibernate.validator.referenceguide.chapter03.returnvalue;
public class RentalStation {
@ValidRentalStation
public RentalStation() {
//...
@NotNull
@Size(min = 1)
public List<Customer> getCustomers() {
//...
return null;
3.1.3. Cascaded validation
Similar to the cascaded validation of JavaBeans properties (see
Object graphs), the @Valid
annotation can be used to mark executable
parameters and return values for cascaded validation. When validating a parameter or return value
annotated with @Valid
, the constraints declared on the parameter or return value object are
validated as well.
In Marking executable parameters and return values for cascaded validation, the car
parameter of the method Garage#checkCar()
as
well as the return value of the Garage
constructor are marked for cascaded validation.
Example 28. Marking executable parameters and return values for cascaded validation
package org.hibernate.validator.referenceguide.chapter03.cascaded;
public class Garage {
@NotNull
private String name;
@Valid
public Garage(String name) {
this.name = name;
public boolean checkCar(@Valid @NotNull Car car) {
//...
return false;
package org.hibernate.validator.referenceguide.chapter03.cascaded;
public class Car {
@NotNull
private String manufacturer;
@NotNull
@Size(min = 2, max = 14)
private String licensePlate;
public Car(String manufacturer, String licencePlate) {
this.manufacturer = manufacturer;
this.licensePlate = licencePlate;
//getters and setters ...
When validating the arguments of the checkCar()
method, the constraints on the properties of the
passed Car
object are evaluated as well. Similarly, the @NotNull
constraint on the name field of
Garage
is checked when validating the return value of the Garage
constructor.
Generally, the cascaded validation works for executables in exactly the same way as it does for
JavaBeans properties.
In particular, null
values are ignored during cascaded validation (naturally this can’t happen
during constructor return value validation) and cascaded validation is performed recursively, i.e.
if a parameter or return value object which is marked for cascaded validation itself has properties
marked with @Valid
, the constraints declared on the referenced elements will be validated as well.
Cascaded validation can not only be applied to simple object references but also to collection-typed
parameters and return values. This means when putting the @Valid
annotation to a parameter or return
value which
each contained element gets validated. So when validating the arguments of the checkCars()
method in
List-typed method parameter marked for cascaded validation, each element instance of the passed list will
be validated and a ConstraintViolation
created when any of the contained Car
instances is invalid.
Example 29. List-typed method parameter marked for cascaded validation
package org.hibernate.validator.referenceguide.chapter03.cascaded.collection;
public class Garage {
public boolean checkCars(@Valid @NotNull List<Car> cars) {
//...
return false;
3.1.4. Method constraints in inheritance hierarchies
When declaring method constraints in inheritance hierarchies, it is important to be aware of the
following rules:
The preconditions to be satisfied by the caller of a method may not be strengthened in subtypes
The postconditions guaranteed to the caller of a method may not be weakened in subtypes
These rules are motivated by the concept of behavioral subtyping which requires that wherever a
type T
is used, also a subtype S
of T
may be used without altering the program’s behavior.
As an example, consider a class invoking a method on an object with the static type T
. If the
runtime type of that object was S
and S
imposed additional preconditions, the client class might
fail to satisfy these preconditions as is not aware of them. The rules of behavioral subtyping are
also known as the Liskov
substitution principle.
The Bean Validation specification implements the first rule by disallowing parameter constraints on
methods which override or implement a method declared in a supertype (superclass or interface).
Illegal method parameter constraint in subtype shows a violation of this rule.
Example 30. Illegal method parameter constraint in subtype
package org.hibernate.validator.referenceguide.chapter03.inheritance.parameter;
public interface Vehicle {
void drive(@Max(75) int speedInMph);
package org.hibernate.validator.referenceguide.chapter03.inheritance.parameter;
public class Car implements Vehicle {
@Override
public void drive(@Max(55) int speedInMph) {
//...
The @Max
constraint on Car#drive()
is illegal since this method implements the interface method
Vehicle#drive()
. Note that parameter constraints on overriding methods are also disallowed, if the
supertype method itself doesn’t declare any parameter constraints.
Furthermore, if a method overrides or implements a method declared in several parallel supertypes
(e.g. two interfaces not extending each other or a class and an interface not implemented by that
class), no parameter constraints may be specified for the method in any of the involved types. The
types in Illegal method parameter constraint in parallel types of a hierarchy demonstrate a violation of that
rule. The method RacingCar#drive()
overrides Vehicle#drive()
as well as Car#drive()
.
Therefore the constraint on Vehicle#drive()
is illegal.
Example 31. Illegal method parameter constraint in parallel types of a hierarchy
package org.hibernate.validator.referenceguide.chapter03.inheritance.parallel;
public interface Vehicle {
void drive(@Max(75) int speedInMph);
package org.hibernate.validator.referenceguide.chapter03.inheritance.parallel;
public interface Car {
void drive(int speedInMph);
package org.hibernate.validator.referenceguide.chapter03.inheritance.parallel;
public class RacingCar implements Car, Vehicle {
@Override
public void drive(int speedInMph) {
//...
The previously described restrictions only apply to parameter constraints. In contrast, return value
constraints may be added in methods overriding or implementing any supertype methods.
In this case, all the method’s return value constraints apply for the subtype method, i.e. the
constraints declared on the subtype method itself as well as any return value constraints on
overridden/implemented supertype methods. This is legal as putting additional return value
constraints in place may never represent a weakening of the postconditions guaranteed to the caller
of a method.
So when validating the return value of the method Car#getPassengers()
shown in
Return value constraints on supertype and subtype method, the @Size
constraint on the method itself as well
as the @NotNull
constraint on the implemented interface method Vehicle#getPassengers()
apply.
Example 32. Return value constraints on supertype and subtype method
package org.hibernate.validator.referenceguide.chapter03.inheritance.returnvalue;
public interface Vehicle {
@NotNull
List<Person> getPassengers();
package org.hibernate.validator.referenceguide.chapter03.inheritance.returnvalue;
public class Car implements Vehicle {
@Override
@Size(min = 1)
public List<Person> getPassengers() {
//...
return null;
The rules described in this section only apply to methods but not constructors. By definition,
constructors never override supertype constructors. Therefore, when validating the parameters or the
return value of a constructor invocation only the constraints declared on the constructor itself
apply, but never any constraints declared on supertype constructors.
Enforcement of these rules may be relaxed by setting the configuration parameters contained in
the MethodValidationConfiguration
property of the HibernateValidatorConfiguration
before creating
the Validator
instance. See also Relaxation of requirements for method validation in class hierarchies.
3.2. Validating method constraints
The validation of method constraints is done using the ExecutableValidator
interface.
In Obtaining an ExecutableValidator
instance you will learn how to obtain an ExecutableValidator
instance while ExecutableValidator
methods shows how to use the different methods
offered by this interface.
Instead of calling the ExecutableValidator
methods directly from within application code, they are
usually invoked via a method interception technology such as AOP, proxy objects, etc. This causes
executable constraints to be validated automatically and transparently upon method or constructor
invocation. Typically a ConstraintViolationException
is raised by the integration layer in case any
of the constraints is violated.
3.2.1. Obtaining an ExecutableValidator
instance
You can retrieve an ExecutableValidator
instance via Validator#forExecutables()
as shown in
Obtaining an ExecutableValidator
instance.
Example 33. Obtaining an ExecutableValidator
instance
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
executableValidator = factory.getValidator().forExecutables();
In the example the executable validator is retrieved from the default validator factory, but if
required you could also bootstrap a specifically configured factory as described in
Bootstrapping, for instance in order to use a specific parameter name provider
(see ParameterNameProvider
).
3.2.2. ExecutableValidator
methods
The ExecutableValidator
interface offers altogether four methods:
Just as the methods on Validator
, all these methods return a Set<ConstraintViolation>
which contains
a ConstraintViolation
instance for each violated constraint and which is empty if the validation
succeeds. Also all the methods have a var-args groups parameter by which you can pass the validation
groups to be considered for validation.
The examples in the following sections are based on the methods on constructors of the Car
class
shown in Class Car
with constrained methods and constructors.
Example 34. Class Car
with constrained methods and constructors
package org.hibernate.validator.referenceguide.chapter03.validation;
public class Car {
public Car(@NotNull String manufacturer) {
//...
@ValidRacingCar
public Car(String manufacturer, String team) {
//...
public void drive(@Max(75) int speedInMph) {
//...
@Size(min = 1)
public List<Passenger> getPassengers() {
//...
return Collections.emptyList();
ExecutableValidator#validateParameters()
The method validateParameters()
is used to validate the arguments of a method invocation.
Using ExecutableValidator#validateParameters()
shows an example. The validation results in a
violation of the @Max
constraint on the parameter of the drive()
method.
Example 35. Using ExecutableValidator#validateParameters()
Car object = new Car( "Morris" );
Method method = Car.class.getMethod( "drive", int.class );
Object[] parameterValues = { 80 };
Set<ConstraintViolation<Car>> violations = executableValidator.validateParameters(
object,
method,
parameterValues
assertEquals( 1, violations.size() );
Class<? extends Annotation> constraintType = violations.iterator()
.next()
.getConstraintDescriptor()
.getAnnotation()
.annotationType();
assertEquals( Max.class, constraintType );
Note that validateParameters()
validates all the parameter constraints of a method, i.e. constraints
on individual parameters as well as cross-parameter constraints.
ExecutableValidator#validateReturnValue()
Using validateReturnValue()
the return value of a method can can be validated. The validation in
Using ExecutableValidator#validateReturnValue()
yields one constraint violation since the
getPassengers()
method is expect to return at least one Passenger
instance.
Example 36. Using ExecutableValidator#validateReturnValue()
Car object = new Car( "Morris" );
Method method = Car.class.getMethod( "getPassengers" );
Object returnValue = Collections.<Passenger>emptyList();
Set<ConstraintViolation<Car>> violations = executableValidator.validateReturnValue(
object,
method,
returnValue
assertEquals( 1, violations.size() );
Class<? extends Annotation> constraintType = violations.iterator()
.next()
.getConstraintDescriptor()
.getAnnotation()
.annotationType();
assertEquals( Size.class, constraintType );
ExecutableValidator#validateConstructorParameters()
The arguments of constructor invocations can be validated with validateConstructorParameters()
as
shown in method Using ExecutableValidator#validateConstructorParameters()
. Due to the
@NotNull
constraint on the manufacturer parameter, the validation call returns one constraint
violation.
Example 37. Using ExecutableValidator#validateConstructorParameters()
Constructor<Car> constructor = Car.class.getConstructor( String.class );
Object[] parameterValues = { null };
Set<ConstraintViolation<Car>> violations = executableValidator.validateConstructorParameters(
constructor,
parameterValues
assertEquals( 1, violations.size() );
Class<? extends Annotation> constraintType = violations.iterator()
.next()
.getConstraintDescriptor()
.getAnnotation()
.annotationType();
assertEquals( NotNull.class, constraintType );
ExecutableValidator#validateConstructorReturnValue()
Finally, by using validateConstructorReturnValue()
you can validate a constructor’s return value. In
Using ExecutableValidator#validateConstructorReturnValue()
, validateConstructorReturnValue()
returns one constraint violation, since the Car
instance returned by the constructor doesn’t satisfy
the @ValidRacingCar
constraint (not shown).
Example 38. Using ExecutableValidator#validateConstructorReturnValue()
//constructor for creating racing cars
Constructor<Car> constructor = Car.class.getConstructor( String.class, String.class );
Car createdObject = new Car( "Morris", null );
Set<ConstraintViolation<Car>> violations = executableValidator.validateConstructorReturnValue(
constructor,
createdObject
assertEquals( 1, violations.size() );
Class<? extends Annotation> constraintType = violations.iterator()
.next()
.getConstraintDescriptor()
.getAnnotation()
.annotationType();
assertEquals( ValidRacingCar.class, constraintType );
3.2.3. ConstraintViolation
methods for method validation
In addition to the methods introduced in ConstraintViolation
methods,
ConstraintViolation
provides two more methods specific to the validation of executable parameters
and return values.
ConstraintViolation#getExecutableParameters()
returns the validated parameter array in case of
method or constructor parameter validation, while ConstraintViolation#getExecutableReturnValue()
provides access to the validated object in case of return value validation.
All the other ConstraintViolation
methods generally work for method validation in the same way as
for validation of beans. Refer to the JavaDoc to learn more about the
behavior of the individual methods and their return values during bean and method validation.
Note that getPropertyPath()
can be very useful in order to obtain detailed information about the
validated parameter or return value, e.g. for logging purposes. In particular, you can retrieve name
and argument types of the concerned method as well as the index of the concerned parameter from the
path nodes. How this can be done is shown in Retrieving method and parameter information.
Example 39. Retrieving method and parameter information
Car object = new Car( "Morris" );
Method method = Car.class.getMethod( "drive", int.class );
Object[] parameterValues = { 80 };
Set<ConstraintViolation<Car>> violations = executableValidator.validateParameters(
object,
method,
parameterValues
assertEquals( 1, violations.size() );
Iterator<Node> propertyPath = violations.iterator()
.next()
.getPropertyPath()
.iterator();
MethodNode methodNode = propertyPath.next().as( MethodNode.class );
assertEquals( "drive", methodNode.getName() );
assertEquals( Arrays.<Class<?>>asList( int.class ), methodNode.getParameterTypes() );
ParameterNode parameterNode = propertyPath.next().as( ParameterNode.class );
assertEquals( "arg0", parameterNode.getName() );
assertEquals( 0, parameterNode.getParameterIndex() );
3.3. Built-in method constraints
In addition to the built-in bean and property-level constraints discussed in
Built-in constraints, Hibernate Validator currently provides one method-level constraint,
@ParameterScriptAssert
. This is a generic cross-parameter constraint which allows to implement
validation routines using any JSR 223 compatible ("Scripting for the JavaTM Platform") scripting
language, provided an engine for this language is available on the classpath.
To refer to the executable’s parameters from within the expression, use their name as obtained from
the active parameter name provider (see ParameterNameProvider
).
Using @ParameterScriptAssert
shows how the validation logic of the @LuggageCountMatchesPassengerCount
constraint from Declaring a cross-parameter constraint could be expressed with the help of
@ParameterScriptAssert
.
Example 40. Using @ParameterScriptAssert
package org.hibernate.validator.referenceguide.chapter03.parameterscriptassert;
public class Car {
@ParameterScriptAssert(lang = "javascript", script = "arg1.size() <= arg0.size() * 2")
public void load(List<Person> passengers, List<PieceOfLuggage> luggage) {
//...
Message interpolation is the process of creating error messages for violated Bean Validation
constraints. In this chapter you will learn how such messages are defined and resolved and how you
can plug in custom message interpolators in case the default algorithm is not sufficient for your
requirements.
4.1. Default message interpolation
Constraint violation messages are retrieved from so called message descriptors. Each constraint
defines its default message descriptor using the message attribute. At declaration time, the default
descriptor can be overridden with a specific value as shown in Specifying a message descriptor using the message attribute.
Example 41. Specifying a message descriptor using the message attribute
package org.hibernate.validator.referenceguide.chapter04;
public class Car {
@NotNull(message = "The manufacturer name must not be null")
private String manufacturer;
//constructor, getters and setters ...
If a constraint is violated, its descriptor will be interpolated by the validation engine using the
currently configured MessageInterpolator
. The interpolated error message can then be retrieved from
the resulting constraint violation by calling ConstraintViolation#getMessage()
.
Message descriptors can contain message parameters as well as message expressions which will be
resolved during interpolation. Message parameters are string literals enclosed in {}
, while
message expressions are string literals enclosed in ${}
. The following algorithm is applied during
method interpolation:
Resolve any message parameters by using them as key for the resource bundle ValidationMessages. If
this bundle contains an entry for a given message parameter, that parameter will be replaced in the
message with the corresponding value from the bundle. This step will be executed recursively in case
the replaced value again contains message parameters. The resource bundle is expected to be provided
by the application developer, e.g. by adding a file named ValidationMessages.properties to the
classpath. You can also create localized error messages by providing locale specific variations of
this bundle, such as ValidationMessages_en_US.properties. By default, the JVM’s default locale
(Locale#getDefault()
) will be used when looking up messages in the bundle.
Resolve any message parameters by using them as key for a resource bundle containing the standard
error messages for the built-in constraints as defined in Appendix B of the Bean Validation
specification. In the case of Hibernate Validator, this bundle is named
org.hibernate.validator.ValidationMessages
. If this step triggers a replacement, step 1 is executed
again, otherwise step 3 is applied.
Resolve any message parameters by replacing them with the value of the constraint annotation member
of the same name. This allows to refer to attribute values of the constraint (e.g. Size#min()
) in
the error message (e.g. "must be at least ${min}").
Resolve any message expressions by evaluating them as expressions of the Unified Expression
Language. See Interpolation with message expressions to learn more about the usage of
Unified EL in error messages.
You can find the formal definition of the interpolation algorithm in section
5.3.1.1 of the Bean
Validation specification.
Since the characters {
, }
and $
have a special meaning in message descriptors they need to be escaped
if you want to use them literally. The following rules apply:
4.1.2. Interpolation with message expressions
As of Hibernate Validator 5 (Bean Validation 1.1) it is possible to use the Unified Expression
Language (as defined by JSR 341) in constraint
violation messages. This allows to define error messages based on conditional logic and also enables
advanced formatting options. The validation engine makes the following objects available in the EL
context:
the currently validated value (property, bean, method parameter etc.) under the name validatedValue
a bean mapped to the name formatter exposing the var-arg method
format(String format, Object… args)
which behaves like
java.util.Formatter.format(String format, Object… args)
.
4.1.3. Examples
Specifying message descriptors shows how to make use of the different options for specifying
message descriptors.
Example 42. Specifying message descriptors
package org.hibernate.validator.referenceguide.chapter04.complete;
public class Car {
@NotNull
private String manufacturer;
@Size(
min = 2,
max = 14,
message = "The license plate '${validatedValue}' must be between {min} and {max} characters long"
private String licensePlate;
@Min(
value = 2,
message = "There must be at least {value} seat${value > 1 ? 's' : ''}"
private int seatCount;
@DecimalMax(
value = "350",
message = "The top speed ${formatter.format('%1$.2f', validatedValue)} is higher " +
"than {value}"
private double topSpeed;
@DecimalMax(value = "100000", message = "Price must not be higher than ${value}")
private BigDecimal price;
public Car(
String manufacturer,
String licensePlate,
int seatCount,
double topSpeed,
BigDecimal price) {
this.manufacturer = manufacturer;
this.licensePlate = licensePlate;
this.seatCount = seatCount;
this.topSpeed = topSpeed;
this.price = price;
//getters and setters ...
Validating an invalid Car
instance yields constraint violations with the messages shown by the
assertions in Expected error messages:
the @NotNull
constraint on the manufacturer
field causes the error message "may not be null", as
this is the default message defined by the Bean Validation specification and no specific descriptor
is given in the message attribute
the @Size
constraint on the licensePlate
field shows the interpolation of message parameters
({min}
, {max}
) and how to add the validated value to the error message using the EL
expression ${validatedValue}
the @Min
constraint on seatCount
demonstrates how use an EL expression with a ternery expression to
dynamically chose singular or plural form, depending on an attribute of the constraint ("There must
be at least 1 seat" vs. "There must be at least 2 seats")
the message for the @DecimalMax
constraint on topSpeed
shows how to format the validated
value using the formatter instance
finally, the @DecimalMax
constraint on price shows that parameter interpolation has precedence over
expression evaluation, causing the $
sign to show up in front of the maximum price
Only actual constraint attributes can be interpolated using message parameters in the form
{attributeName}
. When referring to the validated value or custom expression variables added to the
interpolation context (see HibernateConstraintValidatorContext
), an EL expression in the
form ${attributeName}
must be used.
Car car = new Car( null, "A", 1, 400.123456, BigDecimal.valueOf( 200000 ) );
String message = validator.validateProperty( car, "manufacturer" )
.iterator()
.next()
.getMessage();
assertEquals( "may not be null", message );
message = validator.validateProperty( car, "licensePlate" )
.iterator()
.next()
.getMessage();
assertEquals(
"The license plate 'A' must be between 2 and 14 characters long",
message
message = validator.validateProperty( car, "seatCount" ).iterator().next().getMessage();
assertEquals( "There must be at least 2 seats", message );
message = validator.validateProperty( car, "topSpeed" ).iterator().next().getMessage();
assertEquals( "The top speed 400.12 is higher than 350", message );
message = validator.validateProperty( car, "price" ).iterator().next().getMessage();
assertEquals( "Price must not be higher than $100000", message );
4.2. Custom message interpolation
If the default message interpolation algorithm does not fit your requirements it is also possible to
plug in a custom MessageInterpolator
implementation.
Custom interpolators must implement the interface javax.validation.MessageInterpolator
. Note that
implementations must be thread-safe. It is recommended that custom message interpolators delegate
final implementation to the default interpolator, which can be obtained via
Configuration#getDefaultMessageInterpolator()
.
In order to use a custom message interpolator it must be registered either by configuring it in the
Bean Validation XML descriptor META-INF/validation.xml (see
Configuring the validator factory in validation.xml) or by passing it when bootstrapping a ValidatorFactory
or
Validator
(see MessageInterpolator
and
Configuring a Validator, respectively).
4.2.1. ResourceBundleLocator
In some use cases you want to use the message interpolation algorithm as defined by the Bean
Validation specification, but retrieve error messages from other resource bundles than
ValidationMessages. In this situation Hibernate Validator’s ResourceBundleLocator
SPI can help.
The default message interpolator in Hibernate Validator, ResourceBundleMessageInterpolator
,
delegates retrieval of resource bundles to that SPI. Using an alternative bundle only requires
passing an instance of PlatformResourceBundleLocator
with the bundle name when bootstrapping the
ValidatorFactory
as shown in Using a specific resource bundle.
Example 44. Using a specific resource bundle
Validator validator = Validation.byDefaultProvider()
.configure()
.messageInterpolator(
new ResourceBundleMessageInterpolator(
new PlatformResourceBundleLocator( "MyMessages" )
.buildValidatorFactory()
.getValidator();
Of course you also could implement a completely different ResourceBundleLocator
, which for instance
returns bundles backed by records in a database. In this case you can obtain the default locator via
HibernateValidatorConfiguration#getDefaultResourceBundleLocator()
, which you e.g. could use as
fall-back for your custom locator.
Besides PlatformResourceBundleLocator
, Hibernate Validator provides another resource bundle locator
implementation out of the box, namely AggregateResourceBundleLocator
, which allows to retrieve error
messages from more than one resource bundle. You could for instance use this implementation in a
multi-module application where you want to have one message bundle per module.
Using AggregateResourceBundleLocator
shows how to use AggregateResourceBundleLocator
.
Example 45. Using AggregateResourceBundleLocator
Validator validator = Validation.byDefaultProvider()
.configure()
.messageInterpolator(
new ResourceBundleMessageInterpolator(
new AggregateResourceBundleLocator(
Arrays.asList(
"MyMessages",
"MyOtherMessages"
.buildValidatorFactory()
.getValidator();
Note that the bundles are processed in the order as passed to the constructor. That means if several
bundles contain an entry for a given message key, the value will be taken from the first bundle in
the list containing the key.
All validation methods on Validator
and ExecutableValidator
discussed in earlier chapters also take
a var-arg argument groups. So far we have been ignoring this parameter, but it is time to have a
closer look.
5.1. Requesting groups
Groups allow you to restrict the set of constraints applied during validation. One use case for
validation groups are UI wizards where in each step only a specified subset of constraints should
get validated. The groups targeted are passed as var-arg parameters to the appropriate validate
method.
Let’s have a look at an example. The class Person
in Example class Person
has a @NotNull
constraint on name
. Since no group is specified for this annotation the default group
javax.validation.groups.Default
is assumed.
When more than one group is requested, the order in which the groups are evaluated is not
deterministic. If no group is specified the default group javax.validation.groups.Default
is
assumed.
package org.hibernate.validator.referenceguide.chapter05;
public class Person {
@NotNull
private String name;
public Person(String name) {
this.name = name;
// getters and setters ...
The class Driver
in Driver extends Person
and adds the properties age
and
hasDrivingLicense
. Drivers must be at least 18 years old (@Min(18)
) and have a driving license
(@AssertTrue
). Both constraints defined on these properties belong to the group DriverChecks
which
is just a simple tagging interface.
Using interfaces makes the usage of groups type-safe and allows for easy refactoring. It also means
that groups can inherit from each other via class inheritance. See Group inheritance.
package org.hibernate.validator.referenceguide.chapter05;
public class Driver extends Person {
@Min(
value = 18,
message = "You have to be 18 to drive a car",
groups = DriverChecks.class
public int age;
@AssertTrue(
message = "You first have to pass the driving test",
groups = DriverChecks.class
public boolean hasDrivingLicense;
public Driver(String name) {
super( name );
public void passedDrivingTest(boolean b) {
hasDrivingLicense = b;
public int getAge() {
return age;
public void setAge(int age) {
this.age = age;
package org.hibernate.validator.referenceguide.chapter05;
public interface DriverChecks {
Finally the class Car
(Car) has some constraints which are part of the default group as
well as @AssertTrue
in the group CarChecks
on the property passedVehicleInspection
which indicates
whether a car passed the road worthy tests.
Example 48. Car
package org.hibernate.validator.referenceguide.chapter05;
public class Car {
@NotNull
private String manufacturer;
@NotNull
@Size(min = 2, max = 14)
private String licensePlate;
@Min(2)
private int seatCount;
@AssertTrue(
message = "The car has to pass the vehicle inspection first",
groups = CarChecks.class
private boolean passedVehicleInspection;
@Valid
private Driver driver;
public Car(String manufacturer, String licencePlate, int seatCount) {
this.manufacturer = manufacturer;
this.licensePlate = licencePlate;
this.seatCount = seatCount;
public boolean isPassedVehicleInspection() {
return passedVehicleInspection;
public void setPassedVehicleInspection(boolean passedVehicleInspection) {
this.passedVehicleInspection = passedVehicleInspection;
public Driver getDriver() {
return driver;
public void setDriver(Driver driver) {
this.driver = driver;
// getters and setters ...
package org.hibernate.validator.referenceguide.chapter05;
public interface CarChecks {
The constraints on Person.name
, Car.manufacturer
, Car.licensePlate
and Car.seatCount
all belong to the Default
group
The constraints on Driver.age
and Driver.hasDrivingLicense
belong to DriverChecks
The constraint on Car.passedVehicleInspection
belongs to the group CarChecks
Using validation groups shows how passing different group combinations to the Validator#validate()
method results in different validation results.
Example 49. Using validation groups
// create a car and check that everything is ok with it.
Car car = new Car( "Morris", "DD-AB-123", 2 );
Set<ConstraintViolation<Car>> constraintViolations = validator.validate( car );
assertEquals( 0, constraintViolations.size() );
// but has it passed the vehicle inspection?
constraintViolations = validator.validate( car, CarChecks.class );
assertEquals( 1, constraintViolations.size() );
assertEquals(
"The car has to pass the vehicle inspection first",
constraintViolations.iterator().next().getMessage()
// let's go to the vehicle inspection
car.setPassedVehicleInspection( true );
assertEquals( 0, validator.validate( car, CarChecks.class ).size() );
// now let's add a driver. He is 18, but has not passed the driving test yet
Driver john = new Driver( "John Doe" );
john.setAge( 18 );
car.setDriver( john );
constraintViolations = validator.validate( car, DriverChecks.class );
assertEquals( 1, constraintViolations.size() );
assertEquals(
"You first have to pass the driving test",
constraintViolations.iterator().next().getMessage()
// ok, John passes the test
john.passedDrivingTest( true );
assertEquals( 0, validator.validate( car, DriverChecks.class ).size() );
// just checking that everything is in order now
assertEquals( 0,
validator.validate(
car,
Default.class,
CarChecks.class,
DriverChecks.class
).size()
The first validate()
call in Using validation groups is done using no explicit group. There are no
validation errors, even though the property passedVehicleInspection
is per default false
. However,
the constraint defined on this property does not belong to the default group.
The next validation using the CarChecks
group fails until the car passes the vehicle inspection.
Adding a driver to the car and validating against DriverChecks
again yields one constraint violation
due to the fact that the driver has not yet passed the driving test. Only after setting
passedDrivingTest
to true
the validation against DriverChecks
passes.
The last validate()
call finally shows that all constraints are passing by validating against all
defined groups.
5.2. Group inheritance
In Using validation groups, we need to call validate()
for each validation group, or specify all of
them one by one.
In some situations, you may want to define a group of constraints which includes another group.
You can do that using group inheritance.
In SuperCar, we define a SuperCar
and a group RaceCarChecks
that extends the Default
group.
A SuperCar
must have safety belts to be allowed to run in races.
Example 50. SuperCar
package org.hibernate.validator.referenceguide.chapter05.groupinheritance;
public class SuperCar extends Car {
@AssertTrue(
message = "Race car must have a safety belt",
groups = RaceCarChecks.class
private boolean safetyBelt;
// getters and setters ...
package org.hibernate.validator.referenceguide.chapter05.groupinheritance;
import javax.validation.groups.Default;
public interface RaceCarChecks extends Default {
In the example below, we will check if a SuperCar
with one seat and no security belts is a valid car
and if it is a valid race-car.
Example 51. Using group inheritance
// create a supercar and check that it's valid as a generic Car
SuperCar superCar = new SuperCar( "Morris", "DD-AB-123", 1 );
assertEquals( "must be greater than or equal to 2", validator.validate( superCar ).iterator().next().getMessage() );
// check that this supercar is valid as generic car and also as race car
Set<ConstraintViolation<SuperCar>> constraintViolations = validator.validate( superCar, RaceCarChecks.class );
assertThat( constraintViolations ).extracting( "message" ).containsOnly(
"Race car must have a safety belt",
"must be greater than or equal to 2"
On the first call to validate()
, we do not specify a group. There is one validation error because a
car must have at least one seat. It is the constraint from the Default
group.
On the second call, we specify only the group RaceCarChecks
. There are two validation errors: one
about the missing seat from the Default
group, another one about the fact that there is no safety
belts coming from the RaceCarChecks
group.
5.3. Defining group sequences
By default, constraints are evaluated in no particular order, regardless of which groups they belong
to. In some situations, however, it is useful to control the order constraints are evaluated.
In the example from Using validation groups it could for instance be required that first all default
car constraints are passing before checking the road worthiness of the car. Finally, before driving
away, the actual driver constraints should be checked.
In order to implement such a validation order you just need to define an interface and annotate it
with @GroupSequence
, defining the order in which the groups have to be validated (see
Defining a group sequence). If at least one constraint fails in a sequenced group none of the
constraints of the following groups in the sequence get validated.
Example 52. Defining a group sequence
package org.hibernate.validator.referenceguide.chapter05;
import javax.validation.GroupSequence;
import javax.validation.groups.Default;
@GroupSequence({ Default.class, CarChecks.class, DriverChecks.class })
public interface OrderedChecks {
Groups defining a sequence and groups composing a sequence must not be involved in a cyclic
dependency either directly or indirectly, either through cascaded sequence definition or group
inheritance. If a group containing such a circularity is evaluated, a GroupDefinitionException
is
raised.
Car car = new Car( "Morris", "DD-AB-123", 2 );
car.setPassedVehicleInspection( true );
Driver john = new Driver( "John Doe" );
john.setAge( 18 );
john.passedDrivingTest( true );
car.setDriver( john );
assertEquals( 0, validator.validate( car, OrderedChecks.class ).size() );
5.4.1. @GroupSequence
Besides defining group sequences, the @GroupSequence
annotation also allows to redefine the default
group for a given class. To do so, just add the @GroupSequence
annotation to the class and specify
the sequence of groups which substitute Default for this class within the annotation.
Class RentalCar
with redefined default group introduces a new class RentalCar
with a redefined default group.
Example 54. Class RentalCar
with redefined default group
package org.hibernate.validator.referenceguide.chapter05;
@GroupSequence({ RentalChecks.class, CarChecks.class, RentalCar.class })
public class RentalCar extends Car {
@AssertFalse(message = "The car is currently rented out", groups = RentalChecks.class)
private boolean rented;
public RentalCar(String manufacturer, String licencePlate, int seatCount) {
super( manufacturer, licencePlate, seatCount );
public boolean isRented() {
return rented;
public void setRented(boolean rented) {
this.rented = rented;
package org.hibernate.validator.referenceguide.chapter05;
public interface RentalChecks {
With this definition you can evaluate the constraints belonging to RentalChecks
, CarChecks
and
RentalCar
by just requesting the Default
group as seen in Validating an object with redefined default group.
Example 55. Validating an object with redefined default group
RentalCar rentalCar = new RentalCar( "Morris", "DD-AB-123", 2 );
rentalCar.setPassedVehicleInspection( true );
rentalCar.setRented( true );
Set<ConstraintViolation<RentalCar>> constraintViolations = validator.validate( rentalCar );
assertEquals( 1, constraintViolations.size() );
assertEquals(
"Wrong message",
"The car is currently rented out",
constraintViolations.iterator().next().getMessage()
rentalCar.setRented( false );
constraintViolations = validator.validate( rentalCar );
assertEquals( 0, constraintViolations.size() );
Since there must no cyclic dependency in the group and group sequence definitions one cannot just
add Default
to the sequence redefining Default
for a class. Instead the class itself has to be
added!
The Default
group sequence overriding is local to the class it is defined on and is not propagated
to associated objects. For the example this means that adding DriverChecks
to the default group
sequence of RentalCar
would not have any effects. Only the group Default
will be propagated to the
driver association.
Note that you can control the propagated group(s) by declaring a group conversion rule (see
Group conversion).
5.4.2. @GroupSequenceProvider
In addition to statically redefining default group sequences via @GroupSequence
, Hibernate Validator
also provides an SPI for the dynamic redefinition of default group sequences depending on the object
state.
For that purpose you need to implement the interface DefaultGroupSequenceProvider
and register this
implementation with the target class via the @GroupSequenceProvider
annotation. In the rental car
scenario you could for instance dynamically add the CarChecks
as seen in
Implementing and using a default group sequence provider.
Example 56. Implementing and using a default group sequence provider
package org.hibernate.validator.referenceguide.chapter05.groupsequenceprovider;
public class RentalCarGroupSequenceProvider
implements DefaultGroupSequenceProvider<RentalCar> {
@Override
public List<Class<?>> getValidationGroups(RentalCar car) {
List<Class<?>> defaultGroupSequence = new ArrayList<Class<?>>();
defaultGroupSequence.add( RentalCar.class );
if ( car != null && !car.isRented() ) {
defaultGroupSequence.add( CarChecks.class );
return defaultGroupSequence;
package org.hibernate.validator.referenceguide.chapter05.groupsequenceprovider;
@GroupSequenceProvider(RentalCarGroupSequenceProvider.class)
public class RentalCar extends Car {
@AssertFalse(message = "The car is currently rented out", groups = RentalChecks.class)
private boolean rented;
public RentalCar(String manufacturer, String licencePlate, int seatCount) {
super( manufacturer, licencePlate, seatCount );
public boolean isRented() {
return rented;
public void setRented(boolean rented) {
this.rented = rented;
5.5. Group conversion
What if you wanted to validate the car related checks together with the driver checks? Of course you
could pass the required groups to the validate call explicitly, but what if you wanted to make these
validations occur as part of the Default
group validation? Here @ConvertGroup
comes into play which
allows you during cascaded validation to use a different group than the originally requested one.
Let’s have a look at @ConvertGroup
usage. Here @GroupSequence({
CarChecks.class, Car.class })
is used to combine the car related constraints under the Default
group
(see Redefining the default group sequence). There is also a @ConvertGroup(from = Default.class, to =
DriverChecks.class)
which ensures the Default
group gets converted to the DriverChecks
group during
cascaded validation of the driver association.
Example 57. @ConvertGroup
usage
package org.hibernate.validator.referenceguide.chapter05.groupconversion;
public class Driver {
@NotNull
private String name;
@Min(
value = 18,
message = "You have to be 18 to drive a car",
groups = DriverChecks.class
public int age;
@AssertTrue(
message = "You first have to pass the driving test",
groups = DriverChecks.class
public boolean hasDrivingLicense;
public Driver(String name) {
this.name = name;
public void passedDrivingTest(boolean b) {
hasDrivingLicense = b;
public int getAge() {
return age;
public void setAge(int age) {
this.age = age;
// getters and setters ...
package org.hibernate.validator.referenceguide.chapter05.groupconversion;
@GroupSequence({ CarChecks.class, Car.class })
public class Car {
@NotNull
private String manufacturer;
@NotNull
@Size(min = 2, max = 14)
private String licensePlate;
@Min(2)
private int seatCount;
@AssertTrue(
message = "The car has to pass the vehicle inspection first",
groups = CarChecks.class
private boolean passedVehicleInspection;
@Valid
@ConvertGroup(from = Default.class, to = DriverChecks.class)
private Driver driver;
public Car(String manufacturer, String licencePlate, int seatCount) {
this.manufacturer = manufacturer;
this.licensePlate = licencePlate;
this.seatCount = seatCount;
public boolean isPassedVehicleInspection() {
return passedVehicleInspection;
public void setPassedVehicleInspection(boolean passedVehicleInspection) {
this.passedVehicleInspection = passedVehicleInspection;
public Driver getDriver() {
return driver;
public void setDriver(Driver driver) {
this.driver = driver;
// getters and setters ...
As a result the validation in Test case for @ConvertGroup
succeeds, even though the constraint
on hasDrivingLicense
belongs to the DriverChecks
group and only the Default
group is requested in
the validate()
call.
Example 58. Test case for @ConvertGroup
// create a car and validate. The Driver is still null and does not get validated
Car car = new Car( "VW", "USD-123", 4 );
car.setPassedVehicleInspection( true );
Set<ConstraintViolation<Car>> constraintViolations = validator.validate( car );
assertEquals( 0, constraintViolations.size() );
// create a driver who has not passed the driving test
Driver john = new Driver( "John Doe" );
john.setAge( 18 );
// now let's add a driver to the car
car.setDriver( john );
constraintViolations = validator.validate( car );
assertEquals( 1, constraintViolations.size() );
assertEquals(
"The driver constraint should also be validated as part of the default group",
constraintViolations.iterator().next().getMessage(),
"You first have to pass the driving test"
You can define group conversions wherever @Valid
can be used, namely associations as well as method
and constructor parameters and return values. Multiple conversions can be specified using
@ConvertGroup.List
.
However, the following restrictions apply:
@ConvertGroup
must only be used in combination with @Valid
. If used without, a
ConstraintDeclarationException
is thrown.
It is not legal to have multiple conversion rules on the same element with the same from value.
In this case, a ConstraintDeclarationException
is raised.
The from attribute must not refer to a group sequence. A ConstraintDeclarationException
is
raised in this situation.
Rules are not executed recursively. The first matching conversion rule is used and subsequent rules
are ignored. For example if a set of @ConvertGroup
declarations chains group A
to B
and
B
to C
, the group A
will be converted to B
and not to C
.
The Bean Validation API defines a whole set of standard constraint annotations such as @NotNull
,
@Size
etc. In cases where these built-in constraints are not sufficient, you can easily create
custom constraints tailored to your specific validation requirements.
6.1. Creating a simple constraint
To create a custom constraint, the following three steps are required:
6.1.1. The constraint annotation
This section shows how to write a constraint annotation which can be used to ensure that a given
string is either completely upper case or lower case. Later on this constraint will be applied to
the licensePlate
field of the Car
class from Getting started to ensure, that
the field is always an upper-case string.
The first thing needed is a way to express the two case modes. While you could use String
constants,
a better approach is using a Java 5 enum for that purpose:
Example 59. Enum CaseMode
to express upper vs. lower case
package org.hibernate.validator.referenceguide.chapter06;
public enum CaseMode {
UPPER,
LOWER;
The next step is to define the actual constraint annotation. If you’ve never designed an annotation
before, this may look a bit scary, but actually it’s not that hard:
Example 60. Defining the @CheckCase
constraint annotation
package org.hibernate.validator.referenceguide.chapter06;
@Target({ FIELD, METHOD, PARAMETER, ANNOTATION_TYPE })
@Retention(RUNTIME)
@Constraint(validatedBy = CheckCaseValidator.class)
@Documented
public @interface CheckCase {
String message() default "{org.hibernate.validator.referenceguide.chapter06.CheckCase." +
"message}";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
CaseMode value();
@Target({ FIELD, METHOD, PARAMETER, ANNOTATION_TYPE })
@Retention(RUNTIME)
@Documented
@interface List {
CheckCase[] value();
An annotation type is defined using the @interface
keyword. All attributes of an annotation type are
declared in a method-like manner. The specification of the Bean Validation API demands, that any
constraint annotation defines
an attribute message
that returns the default key for creating error messages in case the
constraint is violated
an attribute groups
that allows the specification of validation groups, to which this constraint
belongs (see Grouping constraints). This must default to an empty array of type Class<?>.
an attribute payload
that can be used by clients of the Bean Validation API to assign custom
payload objects to a constraint. This attribute is not used by the API itself. An example for a
custom payload could be the definition of a severity:
public class ContactDetails {
@NotNull(message = "Name is mandatory", payload = Severity.Error.class)
private String name;
@NotNull(message = "Phone number not specified, but not mandatory",
payload = Severity.Info.class)
private String phoneNumber;
// ...
Now a client can after the validation of a ContactDetails
instance access the severity of a
constraint using ConstraintViolation.getConstraintDescriptor().getPayload()
and adjust its behavior
depending on the severity.
Besides these three mandatory attributes there is another one, value
, allowing for the required case
mode to be specified. The name value
is a special one, which can be omitted when using the
annotation, if it is the only attribute specified, as e.g. in @CheckCase(CaseMode.UPPER)
.
In addition, the constraint annotation is decorated with a couple of meta annotations:
@Target({ FIELD, METHOD, PARAMETER, ANNOTATION_TYPE})
: Defines the supported target element types
for the constraint. @CheckCase
may be used on fields (element type FIELD
), JavaBeans properties as
well as method return values (METHOD
) and method/constructor parameters (PARAMETER
). The element
type ANNOTATION_TYPE
allows for the creation of composed constraints
(see Constraint composition) based on @CheckCase
.
When creating a class-level constraint (see Class-level constraints), the element
type TYPE
would have to be used. Constraints targeting the return value of a constructor need to
support the element type CONSTRUCTOR
. Cross-parameter constraints (see
Cross-parameter constraints) which are used to validate all the parameters of a method
or constructor together, must support METHOD
or CONSTRUCTOR
, respectively.
@Retention(RUNTIME)
: Specifies, that annotations of this type will be available at runtime by the
means of reflection
@Constraint(validatedBy = CheckCaseValidator.class)
: Marks the annotation type as constraint
annotation and specifies the validator to be used to validate elements annotated with @CheckCase
.
If a constraint may be used on several data types, several validators may be specified, one for
each data type.
@Documented
: Says, that the use of @CheckCase
will be contained in the JavaDoc of elements
annotated with it
Finally, there is an inner annotation type named List
. This annotation allows to specify several
@CheckCase
annotations on the same element, e.g. with different validation groups and messages.
While also another name could be used, the Bean Validation specification recommends to use the name
List
and make the annotation an inner annotation of the corresponding constraint type.
6.1.2. The constraint validator
Having defined the annotation, you need to create a constraint validator, which is able to validate
elements with a @CheckCase
annotation. To do so, implement the interface ConstraintValidator
as
shown below:
Example 61. Implementing a constraint validator for the constraint @CheckCase
package org.hibernate.validator.referenceguide.chapter06;
public class CheckCaseValidator implements ConstraintValidator<CheckCase, String> {
private CaseMode caseMode;
@Override
public void initialize(CheckCase constraintAnnotation) {
this.caseMode = constraintAnnotation.value();
@Override
public boolean isValid(String object, ConstraintValidatorContext constraintContext) {
if ( object == null ) {
return true;
if ( caseMode == CaseMode.UPPER ) {
return object.equals( object.toUpperCase() );
else {
return object.equals( object.toLowerCase() );
The ConstraintValidator
interface defines two type parameters which are set in the implementation.
The first one specifies the annotation type to be validated (CheckCase
), the second one the type of
elements, which the validator can handle (String
). In case a constraint supports several data types,
a ConstraintValidator
for each allowed type has to be implemented and registered at the constraint
annotation as shown above.
The implementation of the validator is straightforward. The initialize()
method gives you access to
the attribute values of the validated constraint and allows you to store them in a field of the
validator as shown in the example.
The isValid()
method contains the actual validation logic. For @CheckCase
this is the check whether
a given string is either completely lower case or upper case, depending on the case mode retrieved
in initialize()
. Note that the Bean Validation specification recommends to consider null values as
being valid. If null
is not a valid value for an element, it should be annotated with @NotNull
explicitly.
The ConstraintValidatorContext
Implementing a constraint validator for the constraint @CheckCase
relies on the default error message generation by just returning true
or false
from the isValid()
method. Using the passed ConstraintValidatorContext
object it is possible to either add additional
error messages or completely disable the default error message generation and solely define custom
error messages. The ConstraintValidatorContext
API is modeled as fluent interface and is best
demonstrated with an example:
Example 62. Using ConstraintValidatorContext
to define custom error messages
package org.hibernate.validator.referenceguide.chapter06.constraintvalidatorcontext;
public class CheckCaseValidator implements ConstraintValidator<CheckCase, String> {
private CaseMode caseMode;
@Override
public void initialize(CheckCase constraintAnnotation) {
this.caseMode = constraintAnnotation.value();
@Override
public boolean isValid(String object, ConstraintValidatorContext constraintContext) {
if ( object == null ) {
return true;
boolean isValid;
if ( caseMode == CaseMode.UPPER ) {
isValid = object.equals( object.toUpperCase() );
else {
isValid = object.equals( object.toLowerCase() );
if ( !isValid ) {
constraintContext.disableDefaultConstraintViolation();
constraintContext.buildConstraintViolationWithTemplate(
"{org.hibernate.validator.referenceguide.chapter06." +
"constraintvalidatorcontext.CheckCase.message}"
.addConstraintViolation();
return isValid;
Using ConstraintValidatorContext
to define custom error messages
shows how you can disable the default error message generation and add a custom error message using
a specified message template. In this example the use of the ConstraintValidatorContext
results in
the same error message as the default error message generation.
It is important to add each configured constraint violation by calling addConstraintViolation()
.
Only after that the new constraint violation will be created.
6.1.3. The error message
The last missing building block is an error message which should be used in case a @CheckCase
constraint is violated. To define this, create a file ValidationMessages.properties with the
following contents (see also Default message interpolation):
Example 63. Defining a custom error message for the CheckCase
constraint
org.hibernate.validator.referenceguide.chapter06.CheckCase.message=Case mode must be {value}.
If a validation error occurs, the validation runtime will use the default value, that you specified
for the message attribute of the @CheckCase
annotation to look up the error message in this resource
bundle.
6.1.4. Using the constraint
You can now use the constraint in the Car
class from the Getting started chapter to
specify that the licensePlate
field should only contain upper-case strings:
Example 64. Applying the @CheckCase
constraint
package org.hibernate.validator.referenceguide.chapter06;
public class Car {
@NotNull
private String manufacturer;
@NotNull
@Size(min = 2, max = 14)
@CheckCase(CaseMode.UPPER)
private String licensePlate;
@Min(2)
private int seatCount;
public Car(String manufacturer, String licencePlate, int seatCount) {
this.manufacturer = manufacturer;
this.licensePlate = licencePlate;
this.seatCount = seatCount;
//getters and setters ...
Finally, Validating objects with the @CheckCase
constraint demonstrates how validating a Car
instance with an invalid
license plate causes the @CheckCase
constraint to be violated.
Example 65. Validating objects with the @CheckCase
constraint
//invalid license plate
Car car = new Car( "Morris", "dd-ab-123", 4 );
Set<ConstraintViolation<Car>> constraintViolations =
validator.validate( car );
assertEquals( 1, constraintViolations.size() );
assertEquals(
"Case mode must be UPPER.",
constraintViolations.iterator().next().getMessage()
//valid license plate
car = new Car( "Morris", "DD-AB-123", 4 );
constraintViolations = validator.validate( car );
assertEquals( 0, constraintViolations.size() );
6.2. Class-level constraints
As discussed earlier, constraints can also be applied on the class level to validate the state of an
entire object. Class-level constraints are defined in the same was as are property constraints.
Implementing a class-level constraint shows constraint annotation and validator of the
@ValidPassengerCount
constraint you already saw in use in Class-level constraint.
Example 66. Implementing a class-level constraint
package org.hibernate.validator.referenceguide.chapter06.classlevel;
@Target({ TYPE, ANNOTATION_TYPE })
@Retention(RUNTIME)
@Constraint(validatedBy = { ValidPassengerCountValidator.class })
@Documented
public @interface ValidPassengerCount {
String message() default "{org.hibernate.validator.referenceguide.chapter06.classlevel." +
"ValidPassengerCount.message}";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
package org.hibernate.validator.referenceguide.chapter06.classlevel;
public class ValidPassengerCountValidator
implements ConstraintValidator<ValidPassengerCount, Car> {
@Override
public void initialize(ValidPassengerCount constraintAnnotation) {
@Override
public boolean isValid(Car car, ConstraintValidatorContext context) {
if ( car == null ) {
return true;
return car.getPassengers().size() <= car.getSeatCount();
As the example demonstrates, you need to use the element type TYPE
in the @Target
annotation. This
allows the constraint to be put on type definitions. The validator of the constraint in the example
receives a Car
in the isValid()
method and can access the complete object state to decide whether
the given instance is valid or not.
6.2.1. Custom property paths
By default the constraint violation for a class-level constraint is reported on the level of the
annotated type, e.g. Car
.
In some cases it is preferable though that the violation’s property path refers to one of the
involved properties. For instance you might want to report the @ValidPassengerCount
constraint
against the passengers property instead of the Car
bean.
Adding a new ConstraintViolation
with custom property path
shows how this can be done by using the constraint validator context passed to isValid()
to build a
custom constraint violation with a property node for the property passengers. Note that you also
could add several property nodes, pointing to a sub-entity of the validated bean.
Example 67. Adding a new ConstraintViolation
with custom property path
package org.hibernate.validator.referenceguide.chapter06.custompath;
public class ValidPassengerCountValidator
implements ConstraintValidator<ValidPassengerCount, Car> {
@Override
public void initialize(ValidPassengerCount constraintAnnotation) {
@Override
public boolean isValid(Car car, ConstraintValidatorContext constraintValidatorContext) {
if ( car == null ) {
return true;
boolean isValid = car.getPassengers().size() <= car.getSeatCount();
if ( !isValid ) {
constraintValidatorContext.disableDefaultConstraintViolation();
constraintValidatorContext
.buildConstraintViolationWithTemplate( "{my.custom.template}" )
.addPropertyNode( "passengers" ).addConstraintViolation();
return isValid;
6.3. Cross-parameter constraints
Bean Validation distinguishes between two different kinds of constraints.
Generic constraints (which have been discussed so far) apply to the annotated element, e.g. a type,
field, method parameter or return value etc. Cross-parameter constraints, in contrast, apply to the
array of parameters of a method or constructor and can be used to express validation logic which
depends on several parameter values.
In order to define a cross-parameter constraint, its validator class must be annotated with
@SupportedValidationTarget(ValidationTarget.PARAMETERS)
. The type parameter T
from the
ConstraintValidator
interface must resolve to either Object
or Object[]
in order to receive the
array of method/constructor arguments in the isValid()
method.
The following example shows the definition of a cross-parameter constraint which can be used to
check that two Date
parameters of a method are in the correct order:
Example 68. Cross-parameter constraint
package org.hibernate.validator.referenceguide.chapter06.crossparameter;
@Constraint(validatedBy = ConsistentDateParametersValidator.class)
@Target({ METHOD, CONSTRUCTOR, ANNOTATION_TYPE })
@Retention(RUNTIME)
@Documented
public @interface ConsistentDateParameters {
String message() default "{org.hibernate.validator.referenceguide.chapter04." +
"crossparameter.ConsistentDateParameters.message}";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
The definition of a cross-parameter constraint isn’t any different from defining a generic
constraint, i.e. it must specify the members message()
, groups()
and payload()
and be annotated with
@Constraint
. This meta annotation also specifies the corresponding validator, which is shown in
Generic and cross-parameter constraint. Note that besides the element types METHOD
and CONSTRUCTOR
also ANNOTATION_TYPE
is specified as target of the annotation, in order to enable the creation of
composed constraints based on @ConsistentDateParameters
(see
Constraint composition).
Cross-parameter constraints are specified directly on the declaration of a method or constructor,
which is also the case for return value constraints. In order to improve code readability, it is
therefore recommended to chose constraint names - such as @ConsistentDateParameters
- which make the
constraint target apparent.
package org.hibernate.validator.referenceguide.chapter06.crossparameter;
@SupportedValidationTarget(ValidationTarget.PARAMETERS)
public class ConsistentDateParametersValidator implements
ConstraintValidator<ConsistentDateParameters, Object[]> {
@Override
public void initialize(ConsistentDateParameters constraintAnnotation) {
@Override
public boolean isValid(Object[] value, ConstraintValidatorContext context) {
if ( value.length != 2 ) {
throw new IllegalArgumentException( "Illegal method signature" );
//leave null-checking to @NotNull on individual parameters
if ( value[0] == null || value[1] == null ) {
return true;
if ( !( value[0] instanceof Date ) || !( value[1] instanceof Date ) ) {
throw new IllegalArgumentException(
"Illegal method signature, expected two " +
"parameters of type Date."
return ( (Date) value[0] ).before( (Date) value[1] );
As discussed above, the validation target PARAMETERS
must be configured for a cross-parameter
validator by using the @SupportedValidationTarget
annotation. Since a cross-parameter constraint
could be applied to any method or constructor, it is considered a best practice to check for the
expected number and types of parameters in the validator implementation.
As with generic constraints, null
parameters should be considered valid and @NotNull
on the
individual parameters should be used to make sure that parameters are not null
.
Similar to class-level constraints, you can create custom constraint violations on single parameters
instead of all parameters when validating a cross-parameter constraint. Just obtain a node builder
from the ConstraintValidatorContext
passed to isValid()
and add a parameter node by calling
addParameterNode()
. In the example you could use this to create a constraint violation on the end
date parameter of the validated method.
In rare situations a constraint is both, generic and cross-parameter. This is the case if a
constraint has a validator class which is annotated with
@SupportedValidationTarget({ValidationTarget.PARAMETERS, ValidationTarget.ANNOTATED_ELEMENT})
or if
it has a generic and a cross-parameter validator class.
When declaring such a constraint on a method which has parameters and also a return value, the
intended constraint target can’t be determined. Constraints which are generic and cross-parameter at
the same time, must therefore define a member validationAppliesTo()
which allows the constraint user
to specify the constraint’s target as shown in Generic and cross-parameter constraint.
Example 70. Generic and cross-parameter constraint
package org.hibernate.validator.referenceguide.chapter06.crossparameter;
@Constraint(validatedBy = {
ScriptAssertObjectValidator.class,
ScriptAssertParametersValidator.class
@Target({ TYPE, FIELD, PARAMETER, METHOD, CONSTRUCTOR, ANNOTATION_TYPE })
@Retention(RUNTIME)
@Documented
public @interface ScriptAssert {
String message() default "{org.hibernate.validator.referenceguide.chapter04." +
"crossparameter.ScriptAssert.message}";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
String script();
ConstraintTarget validationAppliesTo() default ConstraintTarget.IMPLICIT;
The @ScriptAssert
constraint has two validators (not shown), a generic and a cross-parameter one and
thus defines the member validationAppliesTo()
. The default value IMPLICIT
allows to derive the
target automatically in situations where this is possible (e.g. if the constraint is declared on a
field or on a method which has parameters but no return value).
If the target can not be determined implicitly, it must be set by the user to either PARAMETERS
or
RETURN_VALUE
as shown in Specifying the target for a generic and cross-parameter constraint.
Example 71. Specifying the target for a generic and cross-parameter constraint
@ScriptAssert(script = "arg1.size() <= arg0", validationAppliesTo = ConstraintTarget.PARAMETERS)
public Car buildCar(int seatCount, List<Passenger> passengers) {
//...
return null;
6.4. Constraint composition
Looking at the licensePlate
field of the Car
class in Applying the @CheckCase
constraint, you see three
constraint annotations already. In complexer scenarios, where even more constraints could be applied
to one element, this might become a bit confusing easily. Furthermore, if there was a licensePlate
field in another class, you would have to copy all constraint declarations to the other class as
well, violating the DRY principle.
You can address this kind of problem by creating higher level constraints, composed from several
basic constraints. Creating a composing constraint @ValidLicensePlate
shows a composed constraint annotation which
comprises the constraints @NotNull
, @Size
and @CheckCase
:
Example 72. Creating a composing constraint @ValidLicensePlate
package org.hibernate.validator.referenceguide.chapter06.constraintcomposition;
@NotNull
@Size(min = 2, max = 14)
@CheckCase(CaseMode.UPPER)
@Target({ METHOD, FIELD, ANNOTATION_TYPE })
@Retention(RUNTIME)
@Constraint(validatedBy = { })
@Documented
public @interface ValidLicensePlate {
String message() default "{org.hibernate.validator.referenceguide.chapter06." +
"constraintcomposition.ValidLicensePlate.message}";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
To create a composed constraint, simply annotate the constraint declaration with its comprising
constraints. If the composed constraint itself requires a validator, this validator is to be
specified within the @Constraint
annotation. For composed constraints which don’t need an additional
validator such as @ValidLicensePlate
, just set validatedBy()
to an empty array.
Using the new composed constraint at the licensePlate
field is fully equivalent to the previous
version, where the three constraints were declared directly at the field itself:
Example 73. Application of composing constraint ValidLicensePlate
package org.hibernate.validator.referenceguide.chapter06.constraintcomposition;
public class Car {
@ValidLicensePlate
private String licensePlate;
//...
The set of ConstraintViolations
retrieved when validating a Car
instance will contain an entry for
each violated composing constraint of the @ValidLicensePlate
constraint. If you rather prefer a
single ConstraintViolation
in case any of the composing constraints is violated, the
@ReportAsSingleViolation
meta constraint can be used as follows:
Example 74. Using @ReportAsSingleViolation
package org.hibernate.validator.referenceguide.chapter06.constraintcomposition.reportassingle;
//...
@ReportAsSingleViolation
public @interface ValidLicensePlate {
String message() default "{org.hibernate.validator.referenceguide.chapter06." +
"constraintcomposition.ValidLicensePlate.message}";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
So far we have used the default configuration source for Bean Validation, namely annotations.
However, there also exist two kinds of XML descriptors allowing configuration via XML. The first
descriptor describes general Bean Validation behaviour and is provided as META-INF/validation.xml.
The second one describes constraint declarations and closely matches the constraint declaration
approach via annotations. Let’s have a look at these two document types.
The XSD files are available via
http://www.jboss.org/xml/ns/javax/validation/configuration and
http://www.jboss.org/xml/ns/javax/validation/mapping.
7.1. Configuring the validator factory in validation.xml
The key to enable XML configuration for Hibernate Validator is the file META-INF/validation.xml.
If this file exists on the classpath its configuration will be applied when the ValidatorFactory
gets created. Validation configuration schema shows a model view of the XML schema to which
validation.xml has to adhere.
validation.xml
shows the several configuration options of validation.xml. All settings are optional and the same
configuration options are also available programmatically through javax.validation.Configuration
. In
fact the XML configuration will be overridden by values explicitly specified via the programmatic
API. It is even possible to ignore the XML configuration completely via
Configuration#ignoreXmlConfiguration()
. See also Configuring a ValidatorFactory
.
Example 75. validation.xml
<validation-config
xmlns="http://jboss.org/xml/ns/javax/validation/configuration"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://jboss.org/xml/ns/javax/validation/configuration">
<default-provider>com.acme.ValidationProvider</default-provider>
<message-interpolator>com.acme.MessageInterpolator</message-interpolator>
<traversable-resolver>com.acme.TraversableResolver</traversable-resolver>
<constraint-validator-factory>
com.acme.ConstraintValidatorFactory
</constraint-validator-factory>
<parameter-name-provider>com.acme.ParameterNameProvider</parameter-name-provider>
<executable-validation enabled="true">
<default-validated-executable-types>
<executable-type>CONSTRUCTORS</executable-type>
<executable-type>NON_GETTER_METHODS</executable-type>
<executable-type>GETTER_METHODS</executable-type>
</default-validated-executable-types>
</executable-validation>
<constraint-mapping>META-INF/validation/constraints-car.xml</constraint-mapping>
<property name="hibernate.validator.fail_fast">false</property>
</validation-config>
There must only be one file named META-INF/validation.xml on the classpath. If more than one is
found an exception is thrown.
The node default-provider
allows to choose the Bean Validation provider. This is useful if there is
more than one provider on the classpath. message-interpolator
, traversable-resolver
,
constraint-validator-factory
and parameter-name-provider
allow to customize the used
implementations for the interfaces MessageInterpolator
, TraversableResolver
,
ConstraintValidatorFactory
and ParameterNameProvider
defined in the javax.validation
package.
See the sub-sections of Configuring a ValidatorFactory
for more information about these
interfaces.
executable-validation
and its subnodes define defaults for method validation. The Bean Validation
specification defines constructor and non getter methods as defaults. The enabled attribute acts as
global switch to turn method validation on and off (see also Declaring and validating method constraints).
Via the constraint-mapping
element you can list an arbitrary number of additional XML files
containing the actual constraint configuration. Mapping file names must be specified using their
fully-qualified name on the classpath. Details on writing mapping files can be found in the next
section.
Last but not least, you can specify provider specific properties via the property
nodes. In the
example we are using the Hibernate Validator specific hibernate.validator.fail_fast
property (see
Fail fast mode).
7.2. Mapping constraints via constraint-mappings
Expressing constraints in XML is possible via files adhering to the schema seen in
Validation mapping schema. Note that these mapping files are only processed if listed via
constraint-mapping in validation.xml.
Bean constraints configured via XML shows how the classes Car and RentalCar from Car resp.
Class RentalCar
with redefined default group could be mapped in XML.
Example 76. Bean constraints configured via XML
<constraint-mappings
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://jboss.org/xml/ns/javax/validation/mapping validation-mapping-1.1.xsd"
xmlns="http://jboss.org/xml/ns/javax/validation/mapping" version="1.1">
<default-package>org.hibernate.validator.referenceguide.chapter05</default-package>
<bean class="Car" ignore-annotations="true">
<field name="manufacturer">
<constraint annotation="javax.validation.constraints.NotNull"/>
</field>
<field name="licensePlate">
<constraint annotation="javax.validation.constraints.NotNull"/>
</field>
<field name="seatCount">
<constraint annotation="javax.validation.constraints.Min">
<element name="value">2</element>
</constraint>
</field>
<field name="driver">
<valid/>
</field>
<getter name="passedVehicleInspection" ignore-annotations="true">
<constraint annotation="javax.validation.constraints.AssertTrue">
<message>The car has to pass the vehicle inspection first</message>
<groups>
<value>CarChecks</value>
</groups>
<element name="max">10</element>
</constraint>
</getter>
</bean>
<bean class="RentalCar" ignore-annotations="true">
<class ignore-annotations="true">
<group-sequence>
<value>RentalCar</value>
<value>CarChecks</value>
</group-sequence>
</class>
</bean>
<constraint-definition annotation="org.mycompany.CheckCase">
<validated-by include-existing-validators="false">
<value>org.mycompany.CheckCaseValidator</value>
</validated-by>
</constraint-definition>
</constraint-mappings>
Method constraints configured via XML shows how the constraints from
Declaring method and constructor parameter constraints, Declaring method and constructor return value constraints
and Specifying a constraint’s target can be expressed in XML.
Example 77. Method constraints configured via XML
<constraint-mappings
xmlns="http://jboss.org/xml/ns/javax/validation/mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=
"http://jboss.org/xml/ns/javax/validation/mapping validation-mapping-1.1.xsd" version="1.1">
<default-package>org.hibernate.validator.referenceguide.chapter07</default-package>
<bean class="RentalStation" ignore-annotations="true">
<constructor>
<return-value>
<constraint annotation="ValidRentalStation"/>
</return-value>
</constructor>
<constructor>
<parameter type="java.lang.String">
<constraint annotation="javax.validation.constraints.NotNull"/>
</parameter>
</constructor>
<method name="getCustomers">
<return-value>
<constraint annotation="javax.validation.constraints.NotNull"/>
<constraint annotation="javax.validation.constraints.Size">
<element name="min">1</element>
</constraint>
</return-value>
</method>
<method name="rentCar">
<parameter type="Customer">
<constraint annotation="javax.validation.constraints.NotNull"/>
</parameter>
<parameter type="java.util.Date">
<constraint annotation="javax.validation.constraints.NotNull"/>
<constraint annotation="javax.validation.constraints.Future"/>
</parameter>
<parameter type="int">
<constraint annotation="javax.validation.constraints.Min">
<element name="value">1</element>
</constraint>
</parameter>
</method>
</bean>
<bean class="Garage" ignore-annotations="true">
<method name="buildCar">
<parameter type="java.util.List"/>
<cross-parameter>
<constraint annotation="ELAssert">
<element name="expression">...</element>
<element name="validationAppliesTo">PARAMETERS</element>
</constraint>
</cross-parameter>
</method>
<method name="paintCar">
<parameter type="int"/>
<return-value>
<constraint annotation="ELAssert">
<element name="expression">...</element>
<element name="validationAppliesTo">RETURN_VALUE</element>
</constraint>
</return-value>
</method>
</bean>
</constraint-mappings>
The XML configuration is closely mirroring the programmatic API. For this reason it should suffice
to just add some comments. default-package
is used for all fields where a class name is expected. If
the specified class is not fully qualified the configured default package will be used. Every
mapping file can then have several bean nodes, each describing the constraints on the entity with
the specified class name.
A given class can only be configured once across all configuration files. The same applies for
constraint definitions for a given constraint annotation. It can only occur in one mapping file. If
these rules are violated a ValidationException
is thrown.
Setting ignore-annotations
to true
means that constraint annotations placed on the configured bean
are ignored. The default for this value is true. ignore-annotations
is also available for the nodes
class
, fields
, getter
, constructor
, method
, parameter
, cross-parameter
and return-value
.
If not explicitly specified on these levels the configured bean value applies.
The nodes class
, field
, getter
, constructor
and method
(and its sub node parameter) determine on
which level the constraint gets placed. The constraint
node is then used to add a constraint on the
corresponding level. Each constraint definition must define the class via the annotation
attribute.
The constraint attributes required by the Bean Validation specification (message
, groups
and
payload
) have dedicated nodes. All other constraint specific attributes are configured using the
element
node.
The class
node also allows to reconfigure the default group sequence (see
Redefining the default group sequence) via the group-sequence
node. Not shown in the example is the use
of convert-group
to
specify group conversions (see Group conversion). This node is available on field
,
getter
, parameter
and return-value
and specifies a from and to attribute to specify the groups.
Last but not least, the list of ConstraintValidator
instances associated to a given constraint
can be altered via the constraint-definition
node. The annotation attribute represents the constraint
annotation being altered. The validated-by
element represent the (ordered) list of ConstraintValidator
implementations associated to the constraint. If include-existing-validator
is set to false
,
validators defined on the constraint annotation are ignored. If set to true
, the list of constraint
validators described in XML is concatenated to the list of validators specified on the annotation.
One use case for constraint-definition is to change the default constraint definition for @URL
.
Historically, Hibernate Validator’s default constraint validator for this constraint uses the
java.net.URL
constructor to verify that an URL is valid.
However, there is also a purely regular expression based version available which can be configured using
Using XML to register a regular expression based constraint definition for @URL
<constraint-definition annotation="org.hibernate.validator.constraints.URL">
<validated-by include-existing-validators="false">
<value>org.hibernate.validator.constraintvalidators.RegexpURLValidator</value>
</validated-by>
</constraint-definition>
In Obtaining a Validator
instance you already saw one way for creating a Validator instance - via
Validation#buildDefaultValidatorFactory()
. In this chapter you will learn how to use the other
methods in javax.validation.Validation
in order to bootstrap specifically configured validators.
8.1. Retrieving ValidatorFactory
and Validator
You obtain a Validator
by retrieving a ValidatorFactory
via one of the static methods on
javax.validation.Validation
and calling getValidator()
on the factory instance.
Bootstrapping default ValidatorFactory
and Validator
shows how to obtain a validator from the default
validator factory:
Example 78. Bootstrapping default ValidatorFactory
and Validator
ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
Validator validator = validatorFactory.getValidator();
The generated ValidatorFactory
and Validator
instances are thread-safe and can be cached. As
Hibernate Validator uses the factory as context for caching constraint metadata it is recommended to
work with one factory instance within an application.
Bean Validation supports working with several providers such as Hibernate Validator within one
application. If more than one provider is present on the classpath, it is not guaranteed which one
is chosen when creating a factory via buildDefaultValidatorFactory()
.
In this case you can explicitly specify the provider to use via Validation#byProvider()
, passing the
provider’s ValidationProvider
class as shown in Bootstrapping ValidatorFactory
and Validator using a specific provider.
Example 79. Bootstrapping ValidatorFactory
and Validator using a specific provider
ValidatorFactory validatorFactory = Validation.byProvider( HibernateValidator.class )
.configure()
.buildValidatorFactory();
Validator validator = validatorFactory.getValidator();
Note that the configuration object returned by configure()
allows to specifically customize the
factory before calling buildValidatorFactory()
. The available options are discussed later in this
chapter.
Similarly you can retrieve the default validator factory for configuration which is demonstrated in
Retrieving the default ValidatorFactory
for configuration.
Example 80. Retrieving the default ValidatorFactory
for configuration
ValidatorFactory validatorFactory = Validation.byDefaultProvider()
.configure()
.buildValidatorFactory();
Validator validator = validatorFactory.getValidator();
8.1.1. ValidationProviderResolver
By default, available Bean Validation providers are discovered using the
Service Provider mechanism.
For that purpose, each provider includes the file META-
INF/services/javax.validation.spi.ValidationProvider, containing the fully qualified classname of
its ValidationProvider
implementation. In the case of Hibernate Validator this is
org.hibernate.validator.HibernateValidator
.
Depending on your environment and its classloading specifics, provider discovery via the Java’s
service loader mechanism might not work. In this case you can plug in a custom
ValidationProviderResolver
implementation which performs the provider retrieval. An example is OSGi,
where you could implement a provider resolver which uses OSGi services for provider discovery.
To use a custom provider resolver pass it via providerResolver()
as shown shown in
Using a custom ValidationProviderResolver
.
Example 81. Using a custom ValidationProviderResolver
package org.hibernate.validator.referenceguide.chapter08;
public class OsgiServiceDiscoverer implements ValidationProviderResolver {
@Override
public List<ValidationProvider<?>> getValidationProviders() {
//...
return null;
ValidatorFactory validatorFactory = Validation.byDefaultProvider()
.providerResolver( new OsgiServiceDiscoverer() )
.configure()
.buildValidatorFactory();
Validator validator = validatorFactory.getValidator();
8.2. Configuring a ValidatorFactory
By default validator factories retrieved from Validation
and any validators they create are
configured as per the XML descriptor META-INF/validation.xml (see Configuring via XML),
if present.
If you want to disable the XML based configuration, you can do so by invoking
Configuration#ignoreXmlConfiguration()
.
The different values of the XML configuration can be accessed via
Configuration#getBootstrapConfiguration()
. This can for instance be helpful if you want to integrate
Bean Validation into a managed environment and want to create managed instances of the objects
configured via XML.
Using the fluent configuration API, you can override one or more of the settings when bootstrapping
the factory. The following sections show how to make use of the different options. Note that the
Configuration
class exposes the default implementations of the different extension points which can
be useful if you want to use these as delegates for your custom implementations.
8.2.1. MessageInterpolator
Message interpolators are used by the validation engine to create user readable error messages from
constraint message descriptors.
In case the default message interpolation algorithm described in Interpolating constraint error messages
is not sufficient for your needs, you can pass in your own implementation of the MessageInterpolator
interface via Configuration#messageInterpolator()
as shown in
Using a custom MessageInterpolator
.
Example 82. Using a custom MessageInterpolator
package org.hibernate.validator.referenceguide.chapter08;
public class MyMessageInterpolator implements MessageInterpolator {
@Override
public String interpolate(String messageTemplate, Context context) {
//...
return null;
@Override
public String interpolate(String messageTemplate, Context context, Locale locale) {
//...
return null;
ValidatorFactory validatorFactory = Validation.byDefaultProvider()
.configure()
.messageInterpolator( new MyMessageInterpolator() )
.buildValidatorFactory();
Validator validator = validatorFactory.getValidator();
8.2.2. TraversableResolver
In some cases the validation engine should not access the state of a bean property. The most obvious
example for that is a lazily loaded property or association of a JPA entity. Validating this lazy
property or association would mean that its state would have to be accessed, triggering a load from
the database.
Which properties can be accessed and which ones not is controlled by querying the
TraversableResolver
interface. Using a custom TraversableResolver
shows how to use a
custom traversable resolver implementation.
Example 83. Using a custom TraversableResolver
package org.hibernate.validator.referenceguide.chapter08;
public class MyTraversableResolver implements TraversableResolver {
@Override
public boolean isReachable(
Object traversableObject,
Node traversableProperty,
Class<?> rootBeanType,
Path pathToTraversableObject,
ElementType elementType) {
//...
return false;
@Override
public boolean isCascadable(
Object traversableObject,
Node traversableProperty,
Class<?> rootBeanType,
Path pathToTraversableObject,
ElementType elementType) {
//...
return false;
ValidatorFactory validatorFactory = Validation.byDefaultProvider()
.configure()
.traversableResolver( new MyTraversableResolver() )
.buildValidatorFactory();
Validator validator = validatorFactory.getValidator();
If no specific traversable resolver has been configured, the default
behavior is to consider all properties as reachable and cascadable.
When using Hibernate Validator together with a JPA 2 provider such as
Hibernate ORM, only those properties will be considered reachable
which already have been loaded by the persistence provider and all
properties will be considered cascadable.
8.2.3. ConstraintValidatorFactory
ConstraintValidatorFactory
is the extension point for customizing how constraint validators are
instantiated and released.
The default ConstraintValidatorFactory
provided by Hibernate Validator requires a public no-arg
constructor to instantiate ConstraintValidator
instances (see The constraint validator).
Using a custom ConstraintValidatorFactory
offers for example the possibility to use dependency
injection in constraint validator implementations.
To configure a custom constraint validator factory call Configuration#constraintValidatorFactory()
(see Using a custom ConstraintValidatorFactory
.
Example 84. Using a custom ConstraintValidatorFactory
package org.hibernate.validator.referenceguide.chapter08;
public class MyConstraintValidatorFactory implements ConstraintValidatorFactory {
@Override
public <T extends ConstraintValidator<?, ?>> T getInstance(Class<T> key) {
//...
return null;
@Override
public void releaseInstance(ConstraintValidator<?, ?> instance) {
//...
ValidatorFactory validatorFactory = Validation.byDefaultProvider()
.configure()
.constraintValidatorFactory( new MyConstraintValidatorFactory() )
.buildValidatorFactory();
Validator validator = validatorFactory.getValidator();
Any constraint implementations relying on ConstraintValidatorFactory
behaviors specific to an
implementation (dependency injection, no no-arg constructor and so on) are not considered portable.
ConstraintValidatorFactory
implementations should not cache validator instances as the state of each
instance can be altered in the initialize()
method.
8.2.4. ParameterNameProvider
In case a method or constructor parameter constraint is violated, the ParameterNameProvider
interface is used to retrieve the parameter name and make it available to the user via the
property path of the constraint violation.
The default implementation returns parameter names in the form of arg0
, arg1
etc, while custom
implementations can retrieve the parameter names using methods such as parameter annotations,
debug symbols, or Java 8 reflection.
An implementation for retrieving the parameter names using reflection in Java 8 is provided with
ReflectionParameterNameProvider
. For this parameter name provider to work, the
source must be compiled using the –parameters
compiler argument. Otherwise, the provider will
return synthetic names in the form of arg0
, arg1
, etc.
To use ReflectionParameterNameProvider
or another custom provider either pass an instance of
the provider during bootstrapping as shown in Using a custom ParameterNameProvider
,
or specify the fully qualified class name of the provider as value for
the <parameter-name-provider>
element in the META-INF/validation.xml file
(see Configuring the validator factory in validation.xml). This is demonstrated in
Using a custom ParameterNameProvider
.
Example 85. Using a custom ParameterNameProvider
package org.hibernate.validator.referenceguide.chapter08;
public class MyParameterNameProvider implements ParameterNameProvider {
@Override
public List<String> getParameterNames(Constructor<?> constructor) {
//...
return null;
@Override
public List<String> getParameterNames(Method method) {
//...
return null;
ValidatorFactory validatorFactory = Validation.byDefaultProvider()
.configure()
.parameterNameProvider( new MyParameterNameProvider() )
.buildValidatorFactory();
Validator validator = validatorFactory.getValidator();
Hibernate Validator comes with a custom ParameterNameProvider
implementation based on the
ParaNamer library which provides several ways
for obtaining parameter names at runtime. Refer to ParaNamer based ParameterNameProvider
to learn more about this specific implementation.
8.2.5. Adding mapping streams
As discussed earlier you can configure the constraints applying for your Java beans using XML based
constraint mappings.
Besides the mapping files specified in META-INF/validation.xml you can add further mappings via
Configuration#addMapping()
(see Adding constraint mapping streams). Note that the passed input
stream(s) must adhere to the XML schema for constraint mappings presented in
Mapping constraints via constraint-mappings
.
Example 86. Adding constraint mapping streams
InputStream constraintMapping1 = null;
InputStream constraintMapping2 = null;
ValidatorFactory validatorFactory = Validation.byDefaultProvider()
.configure()
.addMapping( constraintMapping1 )
.addMapping( constraintMapping2 )
.buildValidatorFactory();
Validator validator = validatorFactory.getValidator();
8.2.6. Provider-specific settings
Via the configuration object returned by Validation#byProvider()
provider specific options can be
configured.
In case of Hibernate Validator this e.g. allows you to enable the fail fast mode and pass one or
more programmatic constraint mappings as demonstrated in
Setting Hibernate Validator specific options.
Example 87. Setting Hibernate Validator specific options
ValidatorFactory validatorFactory = Validation.byProvider( HibernateValidator.class )
.configure()
.failFast( true )
.addMapping( (ConstraintMapping) null )
.buildValidatorFactory();
Validator validator = validatorFactory.getValidator();
Alternatively, provider-specific options can be passed via Configuration#addProperty()
. Hibernate
Validator supports enabling the fail fast mode that way, too:
Example 88. Enabling a Hibernate Validator specific option via addProperty()
ValidatorFactory validatorFactory = Validation.byProvider( HibernateValidator.class )
.configure()
.addProperty( "hibernate.validator.fail_fast", "true" )
.buildValidatorFactory();
Validator validator = validatorFactory.getValidator();
Refer to Fail fast mode and Programmatic constraint definition and declaration to learn more about the fail fast
mode and the constraint declaration API.
8.3. Configuring a Validator
When working with a configured validator factory it can occasionally be required to apply a
different configuration to a single Validator
instance. Configuring a Validator
instance via usingContext()
shows how this can
be achieved by calling ValidatorFactory#usingContext()
.
Example 89. Configuring a Validator
instance via usingContext()
ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
Validator validator = validatorFactory.usingContext()
.messageInterpolator( new MyMessageInterpolator() )
.traversableResolver( new MyTraversableResolver() )
.getValidator();
The Bean Validation specification provides not only a validation engine, but also an API for
retrieving constraint metadata in a uniform way, no matter whether the constraints are declared
using annotations or via XML mappings. Read this chapter to learn more about this API and its
possibilities. You can find all the metadata API types in the package javax.validation.metadata
.
The examples presented in this chapter are based on the classes and constraint declarations shown in
Example classes.
Example 90. Example classes
package org.hibernate.validator.referenceguide.chapter09;
public class Person {
public interface Basic {
@NotNull
private String name;
//getters and setters ...
package org.hibernate.validator.referenceguide.chapter09;
public interface Vehicle {
public interface Basic {
@NotNull(groups = Vehicle.Basic.class)
String getManufacturer();
public class Car implements Vehicle {
public interface SeverityInfo extends Payload {
private String manufacturer;
@NotNull
@Size(min = 2, max = 14)
private String licensePlate;
private Person driver;
private String modelName;
public Car() {
public Car(
@NotNull String manufacturer,
String licencePlate,
Person driver,
String modelName) {
this.manufacturer = manufacturer;
this.licensePlate = licencePlate;
this.driver = driver;
this.modelName = modelName;
public void driveAway(@Max(75) int speed) {
//...
@LuggageCountMatchesPassengerCount(
piecesOfLuggagePerPassenger = 2,
validationAppliesTo = ConstraintTarget.PARAMETERS,
payload = SeverityInfo.class,
message = "There must not be more than {piecesOfLuggagePerPassenger} pieces " +
"of luggage per passenger."
public void load(List<Person> passengers, List<PieceOfLuggage> luggage) {
//...
@Override
@Size(min = 3)
public String getManufacturer() {
return manufacturer;
public void setManufacturer(String manufacturer) {
this.manufacturer = manufacturer;
@Valid
@ConvertGroup(from = Default.class, to = Person.Basic.class)
public Person getDriver() {
return driver;
//further getters and setters...
9.1. BeanDescriptor
The entry point into the metadata API is the method Validator#getConstraintsForClass()
, which
returns an instance of the
BeanDescriptor
interface. Using this
descriptor, you can obtain metadata for constraints declared directly on the bean itself (class- or
property-level), but also retrieve metadata descriptors representing single properties, methods and
constructors.
Using BeanDescriptor
demonstrates how to retrieve a BeanDescriptor
for the
Car
class and how to use this descriptor in form of assertions.
BeanDescriptor carDescriptor = validator.getConstraintsForClass( Car.class );
assertTrue( carDescriptor.isBeanConstrained() );
//one class-level constraint
assertEquals( 1, carDescriptor.getConstraintDescriptors().size() );
//manufacturer, licensePlate, driver
assertEquals( 3, carDescriptor.getConstrainedProperties().size() );
//property has constraint
assertNotNull( carDescriptor.getConstraintsForProperty( "licensePlate" ) );
//property is marked with @Valid
assertNotNull( carDescriptor.getConstraintsForProperty( "driver" ) );
//constraints from getter method in interface and implementation class are returned
assertEquals(
carDescriptor.getConstraintsForProperty( "manufacturer" )
.getConstraintDescriptors()
.size()
//property is not constrained
assertNull( carDescriptor.getConstraintsForProperty( "modelName" ) );
//driveAway(int), load(List<Person>, List<PieceOfLuggage>)
assertEquals( 2, carDescriptor.getConstrainedMethods( MethodType.NON_GETTER ).size() );
//driveAway(int), getManufacturer(), getDriver(), load(List<Person>, List<PieceOfLuggage>)
assertEquals(
carDescriptor.getConstrainedMethods( MethodType.NON_GETTER, MethodType.GETTER )
.size()
//driveAway(int)
assertNotNull( carDescriptor.getConstraintsForMethod( "driveAway", int.class ) );
//getManufacturer()
assertNotNull( carDescriptor.getConstraintsForMethod( "getManufacturer" ) );
//setManufacturer() is not constrained
assertNull( carDescriptor.getConstraintsForMethod( "setManufacturer", String.class ) );
//Car(String, String, Person, String)
assertEquals( 1, carDescriptor.getConstrainedConstructors().size() );
//Car(String, String, Person, String)
assertNotNull(
carDescriptor.getConstraintsForConstructor(
String.class,
String.class,
Person.class,
String.class
You can determine whether the specified class hosts any class- or property-level constraints via
isBeanConstrained()
. Method or constructor constraints are not considered by isBeanConstrained()
.
The method getConstraintDescriptors()
is common to all descriptors derived from ElementDescriptor
(see ElementDescriptor
) and returns a set of descriptors representing the
constraints directly declared on the given element. In case of BeanDescriptor
, the bean’s class-
level constraints are returned. More details on ConstraintDescriptor
can be found in
ConstraintDescriptor
.
Via getConstraintsForProperty()
, getConstraintsForMethod()
and getConstraintsForConstructor()
you
can obtain a descriptor representing one given property or executable element, identified by its
name and, in case of methods and constructors, parameter types. The different descriptor types
returned by these methods are described in the following sections.
Note that these methods consider constraints declared at super-types according to the rules for
constraint inheritance as described in Constraint inheritance. An example is the
descriptor for the manufacturer
property, which provides access to all constraints defined on
Vehicle#getManufacturer()
and the implementing method Car#getManufacturer()
. null
is returned in
case the specified element does not exist or is not constrained.
The methods getConstrainedProperties()
, getConstrainedMethods()
and getConstrainedConstructors()
return (potentially empty) sets with all constrained properties, methods and constructors,
respectively. An element is considered constrained, if it has at least one constraint or is marked
for cascaded validation. When invoking getConstrainedMethods()
, you can specify the type of the
methods to be returned (getters, non-getters or both).
9.2. PropertyDescriptor
The interface
PropertyDescriptor
represents one given property of a
class. It is transparent whether constraints are declared on a field or a property getter, provided
the JavaBeans naming conventions are respected. Using PropertyDescriptor
shows
how to use the PropertyDescriptor
interface.
Example 92. Using PropertyDescriptor
PropertyDescriptor licensePlateDescriptor = carDescriptor.getConstraintsForProperty(
"licensePlate"
//"licensePlate" has two constraints, is not marked with @Valid and defines no group conversions
assertEquals( "licensePlate", licensePlateDescriptor.getPropertyName() );
assertEquals( 2, licensePlateDescriptor.getConstraintDescriptors().size() );
assertTrue( licensePlateDescriptor.hasConstraints() );
assertFalse( licensePlateDescriptor.isCascaded() );
assertTrue( licensePlateDescriptor.getGroupConversions().isEmpty() );
PropertyDescriptor driverDescriptor = carDescriptor.getConstraintsForProperty( "driver" );
//"driver" has no constraints, is marked with @Valid and defines one group conversion
assertEquals( "driver", driverDescriptor.getPropertyName() );
assertTrue( driverDescriptor.getConstraintDescriptors().isEmpty() );
assertFalse( driverDescriptor.hasConstraints() );
assertTrue( driverDescriptor.isCascaded() );
assertEquals( 1, driverDescriptor.getGroupConversions().size() );
Using getConstrainedDescriptors()
, you can retrieve a set of ConstraintDescriptors
providing more
information on the individual constraints of a given property. The method isCascaded()
returns
true
, if the property is marked for cascaded validation (either using the @Valid
annotation or via
XML), false
otherwise. Any configured group conversions are returned by getGroupConversions()
. See
GroupConversionDescriptor
for more details on GroupConversionDescriptor
.
9.3. MethodDescriptor
and ConstructorDescriptor
Constrained methods and constructors are represented by the interfaces
MethodDescriptor
and ConstructorDescriptor
, respectively.
Using MethodDescriptor
and ConstructorDescriptor
demonstrates how to work with these
descriptors.
Example 93. Using MethodDescriptor
and ConstructorDescriptor
//driveAway(int) has a constrained parameter and an unconstrained return value
MethodDescriptor driveAwayDescriptor = carDescriptor.getConstraintsForMethod(
"driveAway",
int.class
assertEquals( "driveAway", driveAwayDescriptor.getName() );
assertTrue( driveAwayDescriptor.hasConstrainedParameters() );
assertFalse( driveAwayDescriptor.hasConstrainedReturnValue() );
//always returns an empty set; constraints are retrievable by navigating to
//one of the sub-descriptors, e.g. for the return value
assertTrue( driveAwayDescriptor.getConstraintDescriptors().isEmpty() );
ParameterDescriptor speedDescriptor = driveAwayDescriptor.getParameterDescriptors()
.get( 0 );
//The "speed" parameter is located at index 0, has one constraint and is not cascaded
//nor does it define group conversions
assertEquals( "arg0", speedDescriptor.getName() );
assertEquals( 0, speedDescriptor.getIndex() );
assertEquals( 1, speedDescriptor.getConstraintDescriptors().size() );
assertFalse( speedDescriptor.isCascaded() );
assert speedDescriptor.getGroupConversions().isEmpty();
//getDriver() has no constrained parameters but its return value is marked for cascaded
//validation and declares one group conversion
MethodDescriptor getDriverDescriptor = carDescriptor.getConstraintsForMethod(
"getDriver"
assertFalse( getDriverDescriptor.hasConstrainedParameters() );
assertTrue( getDriverDescriptor.hasConstrainedReturnValue() );
ReturnValueDescriptor returnValueDescriptor = getDriverDescriptor.getReturnValueDescriptor();
assertTrue( returnValueDescriptor.getConstraintDescriptors().isEmpty() );
assertTrue( returnValueDescriptor.isCascaded() );
assertEquals( 1, returnValueDescriptor.getGroupConversions().size() );
//load(List<Person>, List<PieceOfLuggage>) has one cross-parameter constraint
MethodDescriptor loadDescriptor = carDescriptor.getConstraintsForMethod(
"load",
List.class,
List.class
assertTrue( loadDescriptor.hasConstrainedParameters() );
assertFalse( loadDescriptor.hasConstrainedReturnValue() );
assertEquals(
loadDescriptor.getCrossParameterDescriptor().getConstraintDescriptors().size()
//Car(String, String, Person, String) has one constrained parameter
ConstructorDescriptor constructorDescriptor = carDescriptor.getConstraintsForConstructor(
String.class,
String.class,
Person.class,
String.class
assertEquals( "Car", constructorDescriptor.getName() );
assertFalse( constructorDescriptor.hasConstrainedReturnValue() );
assertTrue( constructorDescriptor.hasConstrainedParameters() );
assertEquals(
constructorDescriptor.getParameterDescriptors()
.get( 0 )
.getConstraintDescriptors()
.size()
getName()
returns the name of the given method or constructor. The methods
hasConstrainedParameters()
and hasConstrainedReturnValue()
can be used to perform a quick check
whether an executable element has any parameter constraints (either constraints on single parameters
or cross-parameter constraints) or return value constraints.
Note that any constraints are not directly exposed on MethodDescriptor
and ConstructorDescriptor
,
but rather on dedicated descriptors representing an executable’s parameters, its return value and
its cross-parameter constraints. To get hold of one of these descriptors, invoke
getParameterDescriptors()
, getReturnValueDescriptor()
or getCrossParameterDescriptor()
,
respectively.
These descriptors provide access to the element’s constraints (getConstraintDescriptors()
) and, in
case of parameters and return value, to its configuration for cascaded validation (isValid()
and
getGroupConversions()
). For parameters, you also can retrieve the index and the name, as returned by
the currently used parameter name provider (see ParameterNameProvider
) via getName()
and getIndex()
.
Getter methods following the JavaBeans naming conventions are considered as bean properties but also
as constrained methods.
That means you can retrieve the related metadata either by obtaining a PropertyDescriptor
(e.g.
BeanDescriptor.getConstraintsForProperty("foo")
) or by examining the return value descriptor of the
getter’s MethodDescriptor
(e.g.
BeanDescriptor.getConstraintsForMethod("getFoo").getReturnValueDescriptor())
.
The ElementDiscriptor
interface is the common base class for the
individual descriptor types such as BeanDescriptor
, PropertyDescriptor
etc. Besides
getConstraintDescriptors()
it provides some more methods common to all descriptors.
hasConstraints()
allows for a quick check whether an element has any direct constraints (e.g. class-
level constraints in case of BeanDescriptor
). getElementClass()
returns the Java type of the element
represented by a given descriptor. More specifically, the method returns
the type of a property or parameter when invoked on PropertyDescriptor
or ParameterDescriptor
respectively,
Object[].class
when invoked on CrossParameterDescriptor
,
the return type when invoked on ConstructorDescriptor
, MethodDescriptor
or ReturnValueDescriptor
.
void.class
will be returned for methods which don’t have a return value.
PropertyDescriptor manufacturerDescriptor = carDescriptor.getConstraintsForProperty(
"manufacturer"
assertTrue( manufacturerDescriptor.hasConstraints() );
assertEquals( String.class, manufacturerDescriptor.getElementClass() );
CrossParameterDescriptor loadCrossParameterDescriptor = carDescriptor.getConstraintsForMethod(
"load",
List.class,
List.class
).getCrossParameterDescriptor();
assertTrue( loadCrossParameterDescriptor.hasConstraints() );
assertEquals( Object[].class, loadCrossParameterDescriptor.getElementClass() );
Finally, ElementDescriptor
offers access to the ConstraintFinder
API which allows you to query for
constraint metadata in a fine grained way. Usage of ConstraintFinder
shows how to retrieve a
ConstraintFinder
instance via findConstraints()
and use the API to query for constraint metadata.
Example 95. Usage of ConstraintFinder
PropertyDescriptor manufacturerDescriptor = carDescriptor.getConstraintsForProperty(
"manufacturer"
//"manufacturer" constraints are declared on the getter, not the field
assertTrue(
manufacturerDescriptor.findConstraints()
.declaredOn( ElementType.FIELD )
.getConstraintDescriptors()
.isEmpty()
//@NotNull on Vehicle#getManufacturer() is part of another group
assertEquals(
manufacturerDescriptor.findConstraints()
.unorderedAndMatchingGroups( Default.class )
.getConstraintDescriptors()
.size()
//@Size on Car#getManufacturer()
assertEquals(
manufacturerDescriptor.findConstraints()
.lookingAt( Scope.LOCAL_ELEMENT )
.getConstraintDescriptors()
.size()
//@Size on Car#getManufacturer() and @NotNull on Vehicle#getManufacturer()
assertEquals(
manufacturerDescriptor.findConstraints()
.lookingAt( Scope.HIERARCHY )
.getConstraintDescriptors()
.size()
//Combining several filter options
assertEquals(
manufacturerDescriptor.findConstraints()
.declaredOn( ElementType.METHOD )
.lookingAt( Scope.HIERARCHY )
.unorderedAndMatchingGroups( Vehicle.Basic.class )
.getConstraintDescriptors()
.size()
Via declaredOn()
you can search for ConstraintDescriptors
declared on certain element types. This is
useful to find property constraints declared on either fields or getter methods.
unorderedAndMatchingGroups()
restricts the resulting constraints to those matching the given
validation group(s).
lookingAt()
allows to distinguish between constraints directly specified on the element
(Scope.LOCAL_ELEMENT
) or constraints belonging to the element but hosted anywhere in the class
hierarchy (Scope.HIERARCHY
).
You can also combine the different options as shown in the last example.
Order is not respected by unorderedAndMatchingGroups()
, but group inheritance and inheritance via
sequence are.
9.5. GroupConversionDescriptor
All those descriptor types that represent elements which can be subject of cascaded validation
(i.e., PropertyDescriptor
, ParameterDescriptor
and ReturnValueDescriptor
) provide access to the
element’s group conversions via getGroupConversions()
. The returned set contains a
GroupConversionDescriptor
for each configured conversion, allowing to retrieve
source and target groups of the conversion. Using GroupConversionDescriptor
shows an example.
Example 96. Using GroupConversionDescriptor
PropertyDescriptor driverDescriptor = carDescriptor.getConstraintsForProperty( "driver" );
Set<GroupConversionDescriptor> groupConversions = driverDescriptor.getGroupConversions();
assertEquals( 1, groupConversions.size() );
GroupConversionDescriptor groupConversionDescriptor = groupConversions.iterator()
.next();
assertEquals( Default.class, groupConversionDescriptor.getFrom() );
assertEquals( Person.Basic.class, groupConversionDescriptor.getTo() );
ConstraintDescriptor
interface describes a
single constraint together with its composing constraints. Via an instance of this interface you get
access to the constraint annotation and its parameters.
Using ConstraintDescriptor
shows how to retrieve default constraint attributes (such as message template, groups etc.) as well
as custom constraint attributes (piecesOfLuggagePerPassenger
) and other metadata such as the
constraint’s annotation type and its validators from a ConstraintDescriptor
.
Example 97. Using ConstraintDescriptor
//descriptor for the @LuggageCountMatchesPassengerCount constraint on the
//load(List<Person>, List<PieceOfLuggage>) method
ConstraintDescriptor<?> constraintDescriptor = carDescriptor.getConstraintsForMethod(
"load",
List.class,
List.class
).getCrossParameterDescriptor().getConstraintDescriptors().iterator().next();
//constraint type
assertEquals(
LuggageCountMatchesPassengerCount.class,
constraintDescriptor.getAnnotation().annotationType()
//standard constraint attributes
assertEquals( SeverityInfo.class, constraintDescriptor.getPayload().iterator().next() );
assertEquals(
ConstraintTarget.PARAMETERS,
constraintDescriptor.getValidationAppliesTo()
assertEquals( Default.class, constraintDescriptor.getGroups().iterator().next() );
assertEquals(
"There must not be more than {piecesOfLuggagePerPassenger} pieces of luggage per " +
"passenger.",
constraintDescriptor.getMessageTemplate()
//custom constraint attribute
assertEquals(
constraintDescriptor.getAttributes().get( "piecesOfLuggagePerPassenger" )
//no composing constraints
assertTrue( constraintDescriptor.getComposingConstraints().isEmpty() );
//validator class
assertEquals(
Arrays.<Class<?>>asList( LuggageCountMatchesPassengerCount.Validator.class ),
constraintDescriptor.getConstraintValidatorClasses()
Hibernate Validator is intended to be used to implement multi-layered data validation, where
constraints are expressed in a single place (the annotated domain model) and checked in various
different layers of the application. For this reason there are multiple integration points with
other technologies.
10.1. ORM integration
Hibernate Validator integrates with both Hibernate and all pure Java Persistence providers.
When lazy loaded associations are supposed to be validated it is recommended to place the constraint
on the getter of the association. Hibernate replaces lazy loaded associations with proxy instances
which get initialized/loaded when requested via the getter. If, in such a case, the constraint is
placed on field level the actual proxy instance is used which will lead to validation errors.
10.1.1. Database schema-level validation
Out of the box, Hibernate (as of version 3.5.x) will translate the constraints you have defined for
your entities into mapping metadata. For example, if a property of your entity is annotated
@NotNull
, its columns will be declared as not null
in the DDL schema generated by Hibernate.
If, for some reason, the feature needs to be disabled, set hibernate.validator.apply_to_ddl
to
false
. See also Bean Validation constraints and Additional constraints.
You can also limit the DDL constraint generation to a subset of the defined constraints by setting
the property org.hibernate.validator.group.ddl
. The property specifies the comma-separated, fully
specified class names of the groups a constraint has to be part of in order to be considered for DDL
schema generation.
10.1.2. Hibernate event-based validation
Hibernate Validator has a built-in Hibernate event listener -
org.hibernate.cfg.beanvalidation.BeanValidationEventListener
-
which is part of Hibernate ORM. Whenever a PreInsertEvent
,
PreUpdateEvent
or PreDeleteEvent
occurs, the listener will verify all constraints of the entity
instance and throw an exception if any constraint is violated. Per default objects will be checked
before any inserts or updates are made by Hibernate. Pre deletion events will per default not
trigger a validation. You can configure the groups to be validated per event type using the
properties javax.persistence.validation.group.pre-persist
,
javax.persistence.validation.group.pre-update
and javax.persistence.validation.group.pre-remove
.
The values of these properties are the comma-separated, fully specified class names of the groups
to validate. Manual configuration of BeanValidationEvenListener
shows the default values for these
properties. In this case they could also be omitted.
On constraint violation, the event will raise a runtime ConstraintViolationException
which contains
a set of ConstraintViolation
instances describing each failure.
If Hibernate Validator is present in the classpath, Hibernate ORM will use it transparently.
To avoid validation even though Hibernate Validator is in the classpath set
javax.persistence.validation.mode
to none.
In case you need to manually set the event listeners for Hibernate ORM, use the following
configuration in hibernate.cfg.xml:
Example 98. Manual configuration of BeanValidationEvenListener
<hibernate-configuration>
<session-factory>
<property name="javax.persistence.validation.group.pre-persist">
javax.validation.groups.Default
</property>
<property name="javax.persistence.validation.group.pre-update">
javax.validation.groups.Default
</property>
<property name="javax.persistence.validation.group.pre-remove"></property>
<event type="pre-update">
<listener class="org.hibernate.cfg.beanvalidation.BeanValidationEventListener"/>
</event>
<event type="pre-insert">
<listener class="org.hibernate.cfg.beanvalidation.BeanValidationEventListener"/>
</event>
<event type="pre-delete">
<listener class="org.hibernate.cfg.beanvalidation.BeanValidationEventListener"/>
</event>
</session-factory>
</hibernate-configuration>
10.1.3. JPA
If you are using JPA 2 and Hibernate Validator is in the classpath the JPA2 specification requires
that Bean Validation gets enabled. The properties javax.persistence.validation.group.pre-persist
,
javax.persistence.validation.group.pre-update
and javax.persistence.validation.group.pre-remove
as
described in Hibernate event-based validation can in this case be configured in
persistence.xml. persistence.xml also defines a node validation-mode which can be set to AUTO
,
CALLBACK
, NONE
. The default is AUTO
.
In a JPA 1 you will have to create and register Hibernate Validator yourself. In case you are using
Hibernate EntityManager you can add a customized version of the BeanValidationEventListener
described in Hibernate event-based validation to your project and register it
manually.
10.2. JSF & Seam
When working with JSF2 or JBoss Seam and Hibernate Validator (Bean Validation) is present in the
runtime environment, validation is triggered for every field in the application. Usage of Bean Validation within JSF2
shows an example of the f:validateBean
tag in a JSF page. The validationGroups
attribute is optional
and can be used to specify a comma separated list of validation groups. The default is
javax.validation.groups.Default
. For more information refer to the Seam documentation or the JSF 2
specification.
Example 99. Usage of Bean Validation within JSF2
<h:form>
<f:validateBean validationGroups="javax.validation.groups.Default">
<h:inputText value=#{model.property}/>
<h:selectOneRadio value=#{model.radioProperty}> ... </h:selectOneRadio>
<!-- other input components here -->
</f:validateBean>
</h:form>
The integration between JSF 2 and Bean Validation is described in the "Bean Validation Integration"
chapter of JSR-314. It is interesting to know that JSF
2 implements a custom MessageInterpolator
to ensure ensure proper localization. To encourage the use
of the Bean Validation message facility, JSF 2 will per default only display the generated Bean
Validation message. This can, however, be configured via the application resource bundle by
providing the following configuration ({0}
is replaced with the Bean Validation message and {1}
is
replaced with the JSF component label):
javax.faces.validator.BeanValidator.MESSAGE={1}: {0}
The default is:
javax.faces.validator.BeanValidator.MESSAGE={0}
10.3. CDI
As of version 1.1, Bean Validation is integrated with CDI (Contexts and Dependency Injection for
JavaTM EE).
This integration provides CDI managed beans for Validator
and ValidatorFactory
and enables
dependency injection in constraint validators as well as custom message interpolators, traversable
resolvers, constraint validator factories and parameter name providers.
Furthermore, parameter and return value constraints on the methods and constructors of CDI managed
beans will automatically be validated upon invocation.
When your application runs on a Java EE container, this integration is enabled by default. When
working with CDI in a Servlet container or in a pure Java SE environment, you can use the CDI
portable extension provided by Hibernate Validator. To do so, add the portable extension to your
class path as described in CDI.
10.3.1. Dependency injection
CDI’s dependency injection mechanism makes it very easy to retrieve ValidatorFactory
and Validator
instances and use them in your managed beans. Just annotate instance fields of your bean with
@javax.inject.Inject
as shown in Retrieving validator factory and validator via @Inject
.
Example 100. Retrieving validator factory and validator via @Inject
package org.hibernate.validator.referenceguide.chapter10.cdi.validator;
@ApplicationScoped
public class RentalStation {
@Inject
private ValidatorFactory validatorFactory;
@Inject
private Validator validator;
//...
The injected beans are the default validator factory and validator instances. In order to configure
them - e.g. to use a custom message interpolator - you can use the Bean Validation XML descriptors
as discussed in Configuring via XML.
If you are working with several Bean Validation providers you can make sure that factory and
validator from Hibernate Validator are injected by annotating the injection points with the
@HibernateValidator
qualifier which is demonstrated in Using the @HibernateValidator
qualifier annotation.
Example 101. Using the @HibernateValidator
qualifier annotation
package org.hibernate.validator.referenceguide.chapter10.cdi.validator.qualifier;
@ApplicationScoped
public class RentalStation {
@Inject
@HibernateValidator
private ValidatorFactory validatorFactory;
@Inject
@HibernateValidator
private Validator validator;
//...
The fully-qualified name of the qualifier annotation is
org.hibernate.validator.cdi.HibernateValidator
. Be sure to not import
org.hibernate.validator.HibernateValidator
instead which is the ValidationProvider
implementation
used for selecting Hibernate Validator when working with the bootstrapping API (see
Retrieving ValidatorFactory
and Validator
).
Via @Inject
you also can inject dependencies into constraint validators and other Bean Validation
objects such as MessageInterpolator
implementations etc.
Constraint validator with injected bean
demonstrates how an injected CDI bean is used in a ConstraintValidator
implementation to determine
whether the given constraint is valid or not. As the example shows, you also can work with the
@PostConstruct
and @PreDestroy
callbacks to implement any required construction and destruction
logic.
Example 102. Constraint validator with injected bean
package org.hibernate.validator.referenceguide.chapter10.cdi.injection;
public class ValidLicensePlateValidator
implements ConstraintValidator<ValidLicensePlate, String> {
@Inject
private VehicleRegistry vehicleRegistry;
@PostConstruct
public void postConstruct() {
//do initialization logic...
@PreDestroy
public void preDestroy() {
//do destruction logic...
@Override
public void initialize(ValidLicensePlate constraintAnnotation) {
@Override
public boolean isValid(String licensePlate, ConstraintValidatorContext constraintContext) {
return vehicleRegistry.isValidLicensePlate( licensePlate );
10.3.2. Method validation
The method interception facilities of CDI allow for a very tight integration with Bean Validation’s
method validation functionality. Just put constraint annotations to the parameters and return values
of the executables of your CDI beans and they will be validated automatically before (parameter
constraints) and after (return value constraints) a method or constructor is invoked.
Note that no explicit interceptor binding is required, instead the required method validation
interceptor will automatically be registered for all managed beans with constrained methods and
constructors.
The interceptor org.hibernate.validator.internal.cdi.interceptor.ValidationInterceptor
is
registered by org.hibernate.validator.internal.cdi.ValidationExtension
. This happens implicitly
within a Java EE 7 runtime environment or explicitly by adding the hibernate-validator-cdi artifact
- see CDI
package org.hibernate.validator.referenceguide.chapter10.cdi.methodvalidation;
@ApplicationScoped
public class RentalStation {
@Valid
public RentalStation() {
//...
@NotNull
@Valid
public Car rentCar(
@NotNull Customer customer,
@NotNull @Future Date startDate,
@Min(1) int durationInDays) {
//...
return null;
@NotNull
List<Car> getAvailableCars() {
//...
return null;
package org.hibernate.validator.referenceguide.chapter10.cdi.methodvalidation;
@RequestScoped
public class RentCarRequest {
@Inject
private RentalStation rentalStation;
public void rentCar(String customerId, Date startDate, int duration) {
//causes ConstraintViolationException
rentalStation.rentCar( null, null, -1 );
Here the RentalStation
bean hosts several method constraints. When invoking one of the RentalStation
methods from another bean such as RentCarRequest
, the constraints of the invoked method are
automatically validated. If any illegal parameter values are passed as in the example, a
ConstraintViolationException
will be thrown by the method interceptor, providing detailed
information on the violated constraints. The same is the case if the method’s return value violates
any return value constraints.
Similarly, constructor constraints are validated automatically upon invocation. In the example the
RentalStation
object returned by the constructor will be validated since the constructor return
value is marked with @Valid
.
Validated executable types
Bean Validation allows for a fine-grained control of the executable types which are automatically
validated. By default, constraints on constructors and non-getter methods are validated. Therefore
the @NotNull
constraint on the method RentalStation#getAvailableCars()
in
CDI managed beans with method-level constraints gets not validated when the method is invoked.
You have the following options to configure which types of executables are validated upon
invocation:
Configure the executable types globally via the XML descriptor META-INF/validation.xml;
see Configuring the validator factory in validation.xml for an example
Use the @ValidateOnExecution
annotation on the executable or type level
If several sources of configuration are specified for a given executable, @ValidateOnExecution
on
the executable level takes precedence over @ValidateOnExecution
on the type level and
@ValidateOnExecution
generally takes precedence over the globally configured types in META-
INF/validation.xml.
Using @ValidateOnExecution
shows how to use the @ValidateOnExecution
annotation:
Example 104. Using @ValidateOnExecution
package org.hibernate.validator.referenceguide.chapter10.cdi.methodvalidation.configuration;
@ApplicationScoped
@ValidateOnExecution(type = ExecutableType.ALL)
public class RentalStation {
@Valid
public RentalStation() {
//...
@NotNull
@Valid
@ValidateOnExecution(type = ExecutableType.NONE)
public Car rentCar(
@NotNull Customer customer,
@NotNull @Future Date startDate,
@Min(1) int durationInDays) {
//...
return null;
@NotNull
public List<Car> getAvailableCars() {
//...
return null;
Here the method rentCar()
won’t be validated upon invocation because it is annotated with
@ValidateOnExecution(type = ExecutableType.NONE)
. In contrast, the constructor and the
method getAvailableCars()
will be validated due to @ValidateOnExecution(type =
ExecutableType.ALL)
being given on the type level. ExecutableType.ALL
is a more compact form for
explicitly specifying all the types CONSTRUCTORS
, GETTER_METHODS
and NON_GETTER_METHODS
.
Executable validation can be turned off globally by specifying
<executable-validation enabled="false"/>
in META-INF/validation.xml. In this case, any
@ValidateOnExecution
annotations are ignored.
Note that when a method overrides or implements a super-type method the configuration will be taken
from that overridden or implemented method (as given via @ValidateOnExecution
on the method itself
or on the super-type). This protects a client of the super-type method from an unexpected alteration
of the configuration, e.g. disabling validation of an overridden executable in a sub-type.
In case a CDI managed bean overrides or implements a super-type method and this super-type method
hosts any constraints, it can happen that the validation interceptor is not properly registered with
the bean, resulting in the bean’s methods not being validated upon invocation. In this case you can
specify the executable type IMPLICIT
on the sub-class as shown in
Using