Chapter 4. Hibernate Validator
Prev |  | Next

## Chapter 4. Hibernate Validator

Annotations are a very convenient and elegant way to specify invariant constraints for a domain model. You can, for example, express that a property should never be null, that the account balance should be strictly positive, etc. These domain model constraints are declared in the bean itself by annotating its properties. A validator can then read them and check for constraint violations. The validation mechanism can be executed in different layers in your application without having to duplicate any of these rules (presentation layer, data access layer). Hibernate Validator has been designed for that purpose.

Hibernate Validator works at two levels. First, it is able to check in-memory instances of a class for constraint violations. Second, it can apply the constraints to the Hibernate metamodel and incorporate them into the generated database schema.

Each constraint annotation is associated to a validator implementation responsible for checking the constraint on the entity instance. A validator can also (optionally) apply the constraint to the Hibernate metamodel, allowing Hibernate to generate DDL that expresses the constraint. With the appropriate event listener, you can execute the checking operation on inserts and updates done by Hibernate. Hibernate Validator is not limited to use with Hibernate. You can easily use it anywhere in your application.

When checking instances at runtime, Hibernate Validator returns information about constraint violations in an array of `InvalidValue`s. Among other information, the `InvalidValue` contains an error description message that can embed the parameter values bundle with the annotation (eg. length limit), and message strings that may be externalized to a `ResourceBundle`.

## 4.1. Constraints

### 4.1.1. What is a constraint?

A constraint is represented by an annotation. A constraint usually has some attributes used to parameterize the constraints limits. The constraint apply to the annotated element.

### 4.1.2. Built in constraints

Hibernate Validator comes with some built-in constraints, which covers most basic data checks. As we'll see later, you're not limited to them, you can in a minute write your own constraints.

Table 4.1. Built-in constraints

Annotation | Apply on | Runtime checking | Hibernate Metadata impact
--- | --- | --- | ---
@Length(min=, max=) | property (String) | check if the string length match the range | Column length will be set to max
@Max(value=) | property (numeric or string representation of a numeric) | check if the value is less than or equals to max | Add a check constraint on the column
@Min(value=) | property (numeric or string representation of a numeric) | check if the value is more than or equals to min | Add a check constraint on the column
@NotNull | property | check if the value is not null | Column(s) are not null
@Past | property (date or calendar) | check if the date is in the past | Add a check constraint on the column
@Future | property (date or calendar) | check if the date is in the future | none
@Pattern(regex="regexp", flag=) | property (string) | check if the property match the regular expression given a match flag (see `java.util.regex.Pattern` ) | none
@Range(min=, max=) | property (numeric or string representation of a numeric) | check if the value is between min and max (included) | Add a check constraint on the column
@Size(min=, max=) | property (array, collection, map) | check if the element size is between min and max (included) | none
@AssertFalse | property | check that the method evaluates to false (useful for constraints expressed in code rather than annotations) | none
@AssertTrue | property | check that the method evaluates to true (useful for constraints expressed in code rather than annotations) | none
@Valid | property (object) | perform 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. | none
@Email | property (String) | check whether the string is conform to the email address specification | none

### 4.1.3. Error messages

Hibernate Validator comes with a default set of error messages translated in a few languages (if yours is not part of it, please sent us a patch). You can override those messages by creating a `ValidatorMessages.properties` or (`ValidatorMessages_loc.properties`) out of `org.hibernate.validator.resources.DefaultValidatorMessages.properties` and change the appropriate keys. You can even add your own additional set of messages while writing your validator annotations.

Alternatively you can provide a `ResourceBundle` while checking programmatically the validation rules on a bean.

### 4.1.4. Writing your own constraints

Extending the set of built-in constraints is extremely easy. Any constraint consists of two pieces: the constraint descriptor (the annotation) and the constraint validator (the implementation class). Here is a simple user-defined descriptor:

    @ValidatorClass(CapitalizedValidator.class)
    @Target(METHOD)
    @Retention(RUNTIME)
    @Documented
    public @interface Capitalized {
        CapitalizeType type() default Capitalize.FIRST;
        String message() default "has incorrect capitalization";
    }

`type` is a parameter describing how the property should to be capitalized. This is a user parameter fully dependant on the annotation business.

`message` is the default string used to describe the constraint violation and is mandatory. You can hard code the string or you can externalize part/all of it through the Java ResourceBundle mechanism. Parameters values are going to be injected inside the message when the `{parameter}` string is found (in our example `Capitalization is not {type}` would generate `Capitalization is not FIRST`), externalizing the whole string in `ValidatorMessages.properties` is considered good practice. See Error messages.

    @ValidatorClass(CapitalizedValidator.class)
    @Target(METHOD)
    @Retention(RUNTIME)
    @Documented
    public @interface Capitalized {
        CapitalizeType type() default Capitalize.FIRST;
        String message() default "{validator.capitalized}";
    }

    ...
    #in ValidatorMessages.properties
    validator.capitalized=Capitalization is not {type}

As you can see the {} notation is recursive.

To link a descriptor to its validator implementation, we use the `@ValidatorClass` meta-annotation. The validator class parameter must name a class which implements `Validator<ConstraintAnnotation>`.

We now have to implement the validator (ie. the rule checking implementation). A validation implementation can check the value of the a property (by implementing `PropertyConstraint`) and/or can modify the hibernate mapping metadata to express the constraint at the database level (by implementing `PersistentClassConstraint`).

    public class CapitalizedValidator
            implements Validator<Capitalized>, PropertyConstraint {
        private CapitalizeType type;

        //part of the Validator<Annotation> contract,
        //allows to get and use the annotation values
        public void initialize(Capitalized parameters) {
            type = parameters.type();
        }

        //part of the property constraint contract
        public boolean isValid(Object value) {
            if (value==null) return true;
            if ( !(value instanceof String) ) return false;
            String string = (String) value;
            if (type == CapitalizeType.ALL) {
                return string.equals( string.toUpperCase() );
            }
            else {
                String first = string.substring(0,1);
                return first.equals( first.toUpperCase();
            }
        }
    }

The `isValid()` method should return false if the constraint has been violated. For more examples, refer to the built-in validator implementations.

We only have seen property level validation, but you can write a Bean level validation annotation. Instead of receiving the return instance of a property, the bean itself will be passed to the validator. To activate the validation checking, just annotated the bean itself instead. A small sample can be found in the unit test suite.

### 4.1.5. Annotating your domain model

Since you are already familiar with annotations now, the syntax should be very familiar.

    public class Address {
        private String line1;
        private String line2;
        private String zip;
        private String state;
        private String country;
        private long id;

        // a not null string of 20 characters maximum
        @Length(max=20)
        @NotNull
        public String getCountry() {
            return country;
        }

        // a non null string
        @NotNull
        public String getLine1() {
            return line1;
        }

        //no constraint
        public String getLine2() {
            return line2;
        }

        // a not null string of 3 characters maximum
        @Length(max=3) @NotNull
        public String getState() {
            return state;
        }

        // a not null numeric string of 5 characters maximum
        // if the string is longer, the message will
        //be searched in the resource bundle at key 'long'
        @Length(max=5, message="{long}")
        @Pattern(regex="[0-9]+")
        @NotNull
        public String getZip() {
            return zip;
        }

        // should always be true
        @AssertTrue
        public boolean isValid() {
            return true;
        }

        // a numeric between 1 and 2000
        @Id @Min(1)
        @Range(max=2000)
        public long getId() {
            return id;
        }
    }

While the example only shows public property validation, you can also annotate fields of any kind of visibility.

    @MyBeanConstraint(max=45)
    public class Dog {
        @AssertTrue private boolean isMale;
        @NotNull protected String getName() { ... };
        ...
    }

You can also annotate interfaces. Hibernate Validator will check all superclasses and interfaces extended or implemented by a given bean to read the appropriate validator annotations.

    public interface Named {
        @NotNull String getName();
        ...
    }

    public class Dog implements Named {

        @AssertTrue private boolean isMale;

        public String getName() { ... };

    }

The name property will be checked for nullity when the Dog bean is validated.

## 4.2. Using the Validator framework

Hibernate Validator is intended to be used to implement multi-layered data validation, where we express constraints in one place (the annotated domain model) and apply them at various different layers of the application.

### 4.2.1. Database schema-level validation

Out of the box, Hibernate Annotations 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.

### 4.2.2. Hibernate event-based validation

Hibernate Validator has two built-in Hibernate event listeners. Whenever a `PreInsertEvent` or `PreUpdateEvent` occurs, the listeners will verify all constraints of the entity instance and throw an exception if any constraint is violated. Basically, objects will be checked before any inserts and before any updates made by Hibernate. This is the most convenient and the easiest way to activate the validation process. On constraint violation, the event will raise a runtime `InvalidStateException` which contains an array of `InvalidValue`s describing each failure.

    <hibernate-configuration>
        ...
        <event type="pre-update">
            <listener
              class="org.hibernate.validator.event.ValidatePreUpdateEventListener"/>
        </event>
        <event type="pre-insert">
            <listener
              class="org.hibernate.validator.event.ValidatePreInsertEventListener"/>
        </event>
    </hibernate-configuration>

### Note

When using Hibernate Entity Manager, the Validation framework is activated out of the box. If the beans are not annotated with validation annotations, there is no performance cost.

### 4.2.3. Application-level validation

Hibernate Validator can be applied anywhere in your application code.

    ClassValidator personValidator = new ClassValidator( Person.class );
    ClassValidator addressValidator = new ClassValidator( Address.class, ResourceBundle.getBundle("messages", Locale.ENGLISH) );

    InvalidValue[] validationMessages = addressValidator.getInvalidValues(address);

The first two lines prepare the Hibernate Validator for class checking. The first one relies upon the error messages embedded in Hibernate Validator (see Error messages), the second one uses a resource bundle for these messages. It is considered a good practice to execute these lines once and cache the validator instances.

The third line actually validates the `Address` instance and returns an array of `InvalidValue`s. Your application logic will then be able to react to the failure.

You can also check a particular property instead of the whole bean. This might be useful for property per property user interaction

    ClassValidator addressValidator = new ClassValidator( Address.class, ResourceBundle.getBundle("messages", Locale.ENGLISH) );

    //only get city property invalid values
    InvalidValue[] validationMessages = addressValidator.getInvalidValues(address, "city");

    //only get potential city property invalid values
    InvalidValue[] validationMessages = addressValidator.getPotentialInvalidValues("city", "Paris")

### 4.2.4. Validation informations

As a validation information carrier, hibernate provide an array of `InvalidValue`. Each `InvalidValue` has a buch of methods describing the individual issues.

`getBeanClass()` retrieves the failing bean type

`getBean()`retrieves the failing instance (if any ie not when using `getPotentianInvalidValues()`)

`getValue()` retrieves the failing value

`getMessage()` retrieves the proper internationalized error message

`getRootBean()` retrieves the root bean instance generating the issue (useful in conjunction with `@Valid`), is null if getPotentianInvalidValues() is used.

`getPropertyPath()` retrieves the dotted path of the failing property starting from the root bean

Prev | Up | Next
Chapter 3. Overriding metadata through XML | Home | Chapter 5. Hibernate Lucene Integration