Chapter 13. Bean Validation

13.1. About Bean Validation

Bean Validation, or JavaBeans Validation, is a model for validating data in Java objects. The model uses built-in and custom annotation constraints to ensure the integrity of application data. The specification is documented here: JSR 349: Bean Validation 1.1.

Hibernate Validator is the JBoss EAP implementation of Bean Validation. It is also the reference implementation of the JSR.

JBoss EAP is 100% compliant with JSR 349 Bean Validation 1.1 specification. Hibernate Validator also provides additional features to the specification.

To get started with Bean Validation, see the bean-validation quickstart that ships with JBoss EAP. For information about how to download and run the quickstarts, see Using the Quickstart Examples in the JBoss EAP Getting Started Guide.

JBoss EAP 7.1 now includes Hibernate Validator 5.3.x.

New Features of Hibernate Validator 5.3.x
  • Programmatic API for constraint definition and declaration.

    Hibernate Validator introduces a new fluid API, more consistent than what existed in previous releases.

    For example, if you want to define a new ValidPassengerCount constraint annotation which relies on a ValidPassengerCountValidator validator, you can use the API as follows:

    ConstraintMapping constraintMapping = configuration.createConstraintMapping();
    
    constraintMapping
        .constraintDefinition( ValidPassengerCount.class )
            .validatedBy( ValidPassengerCountValidator.class );

    It can also be used to replace the implementation of the validator used for a given annotation constraint.

    For more information on this, see Hibernate Validator 5.3.0.CR1 is out.

  • Constraint mapping contributors.

    With the new hibernate.validator.constraint_mapping_contributors property you can now declare several constraint mapping contributors separated by a comma.

    Note

    In Hibernate Validator 5.3.x, the existing hibernate.validator.constraint_mapping_contributor property is still supported, but has been deprecated.

  • Dynamic payloads for constraints.

    Hibernate Validator 5.3.x allows you to enrich custom constraint violations with additional context data. Code examining constraint violations can access and interpret this data in a safer way than by parsing string-based constraint violation messages. This is like a dynamic variant of the existing bean validation payload feature.

    For more information on this, see Hibernate Validator 5.3.0.Alpha1 is out.

  • Email validation.

    The way email validation is done has been changed. The domain of the email now needs to be a valid domain with each label being at most 63 characters long.

13.2. Validation Constraints

13.2.1. About Validation Constraints

Validation constraints are rules applied to a Java element, such as a field, property or bean. A constraint will usually have a set of attributes used to set its limits. There are predefined constraints, and custom ones can be created. Each constraint is expressed in the form of an annotation.

The built-in validation constraints for Hibernate Validator are listed here: Hibernate Validator Constraints.

13.2.2. Hibernate Validator Constraints

Note

When applicable, the application-level constraints lead to creation of database-level constraints that are described in the Hibernate Metadata Impact column in the table below.

Java-specific Validation Constraints

The following table includes validation constraints defined in the Java specifications, which are included in the javax.validation.constraints package.

AnnotationProperty typeRuntime checkingHibernate Metadata impact

@AssertFalse

Boolean

Check that the method evaluates to false. Useful for constraints expressed in code rather than annotations.

None.

@AssertTrue

Boolean

Check that the method evaluates to true. Useful for constraints expressed in code rather than annotations.

None.

@Digits(integerDigits=1)

Numeric or string representation of a numeric

Check whether the property is a number having up to integerDigits integer digits and fractionalDigits fractional digits.

Define column precision and scale.

@Future

Date or calendar

Check if the date is in the future.

None.

@Max(value=)

Numeric or string representation of a numeric

Check if the value is less than or equal to max.

Add a check constraint on the column.

@Min(value=)

Numeric or string representation of a numeric

Check if the value is more than or equal to Min.

Add a check constraint on the column.

@NotNull

 

Check if the value is not null.

Column(s) are not null.

@Past

Date or calendar

Check if the date is in the past.

Add a check constraint on the column.

@Pattern(regexp="regexp", flag=) or @Patterns( {@Pattern(…​)} )

String

Check if the property matches the regular expression given a match flag. See java.util.regex.Pattern.

None.

@Size(min=, max=)

Array, collection, map

Check if the element size is between min and max, both values included.

None.

@Valid

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.

Note

The parameter @Valid is a part of the Bean Validation specification, even though it is located in the javax.validation.constraints package.

Hibernate Validator-specific Validation Constraints

The following table includes vendor-specific validation constraints, which are a part of the org.hibernate.validator.constraints package.

AnnotationProperty typeRuntime checkingHibernate Metadata impact

@Length(min=, max=)

String

Check if the string length matches the range.

Column length will be set to max.

@CreditCardNumber

String

Check whether the string is a well formatted credit card number, derivative of the Luhn algorithm.

None.

@EAN

String

Check whether the string is a properly formatted EAN or UPC-A code.

None.

@Email

String

Check whether the string is conform to the e-mail address specification.

None.

@NotEmpty

 

Check if the string is not null nor empty. Check if the connection is not null nor empty.

Columns are not null for String.

@Range(min=, max=)

Numeric or string representation of a numeric

Check if the value is between min and max, both values included.

Add a check constraint on the column.

13.2.3. Bean Validation Using Custom Constraints

Bean Validation API defines a set of standard constraint annotations, such as @NotNull, @Size, and so on. However, in cases where these predefined constraints are not sufficient, you can easily create custom constraints tailored to your specific validation requirements.

Creating a Bean Validation custom constraint requires that you create a constraint annotation and implement a constraint validator. The following abbreviated code examples are taken from the bean-validation-custom-constraint quickstart that ships with JBoss EAP. See that quickstart for a complete working example.

13.2.3.1. Creating A Constraint Annotation

The following example shows the personAddress field of entity Person is validated using a set of custom constraints defined in the class AddressValidator.

  1. Create the entity Person.

    Example: Person Class

    package org.jboss.as.quickstarts.bean_validation_custom_constraint;
    
    @Entity
    @Table(name = "person")
    public class Person implements Serializable {
    
        private static final long serialVersionUID = 1L;
    
        @Id
        @GeneratedValue
        @Column(name = "person_id")
        private Long personId;
    
        @NotNull
    
        @Size(min = 4)
        private String firstName;
    
        @NotNull
        @Size(min = 4)
        private String lastName;
    
        // Custom Constraint @Address for bean validation
        @NotNull
        @Address
        @OneToOne(mappedBy = "person", cascade = CascadeType.ALL)
        private PersonAddress personAddress;
    
        public Person() {
    
        }
    
        public Person(String firstName, String lastName, PersonAddress address) {
            this.firstName = firstName;
            this.lastName = lastName;
            this.personAddress = address;
        }
    
        /* getters and setters omitted for brevity*/
    }

  2. Create the constraint validator files.

    Example: Address Interface

    package org.jboss.as.quickstarts.bean_validation_custom_constraint;
    
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    import javax.validation.Constraint;
    import javax.validation.Payload;
    
    // Linking the AddressValidator class with @Address annotation.
    @Constraint(validatedBy = { AddressValidator.class })
    // This constraint annotation can be used only on fields and method parameters.
    @Target({ ElementType.FIELD, ElementType.PARAMETER })
    @Retention(value = RetentionPolicy.RUNTIME)
    @Documented
    public @interface Address {
    
        // The message to return when the instance of MyAddress fails the validation.
        String message() default "Address Fields must not be null/empty and obey character limit constraints";
    
        Class<?>[] groups() default {};
    
        Class<? extends Payload>[] payload() default {};
    }

    Example: PersonAddress Class

    package org.jboss.as.quickstarts.bean_validation_custom_constraint;
    
    import java.io.Serializable;
    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.GenerationType;
    import javax.persistence.Id;
    import javax.persistence.OneToOne;
    import javax.persistence.PrimaryKeyJoinColumn;
    import javax.persistence.Table;
    
    @Entity
    @Table(name = "person_address")
    public class PersonAddress implements Serializable {
    
        private static final long serialVersionUID = 1L;
    
        @Id
        @Column(name = "person_id", unique = true, nullable = false)
        @GeneratedValue(strategy = GenerationType.SEQUENCE)
        private Long personId;
    
        private String streetAddress;
        private String locality;
        private String city;
        private String state;
        private String country;
        private String pinCode;
    
        @OneToOne
        @PrimaryKeyJoinColumn
        private Person person;
    
        public PersonAddress() {
    
        }
    
        public PersonAddress(String streetAddress, String locality, String city, String state, String country, String pinCode) {
            this.streetAddress = streetAddress;
            this.locality = locality;
            this.city = city;
            this.state = state;
            this.country = country;
            this.pinCode = pinCode;
        }
    
        /* getters and setters omitted for brevity*/
    }

13.2.3.2. Implementing A Constraint Validator

Having defined the annotation, you need to create a constraint validator that is able to validate elements with an @Address annotation. To do so, implement the interface ConstraintValidator as shown below:

Example: AddressValidator Class

package org.jboss.as.quickstarts.bean_validation_custom_constraint;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import org.jboss.as.quickstarts.bean_validation_custom_constraint.PersonAddress;

public class AddressValidator implements ConstraintValidator<Address, PersonAddress> {

    public void initialize(Address constraintAnnotation) {
    }

    /**
     * 1. A null address is handled by the @NotNull constraint on the @Address.
     * 2. The address should have all the data values specified.
     * 3. Pin code in the address should be of at least 6 characters.
     * 4. The country in the address should be of at least 4 characters.
     */
    public boolean isValid(PersonAddress value, ConstraintValidatorContext context) {
        if (value == null) {
            return true;
        }

        if (value.getCity() == null || value.getCountry() == null || value.getLocality() == null
            || value.getPinCode() == null || value.getState() == null || value.getStreetAddress() == null) {
            return false;
        }

        if (value.getCity().isEmpty()
            || value.getCountry().isEmpty() || value.getLocality().isEmpty()
            || value.getPinCode().isEmpty() || value.getState().isEmpty() || value.getStreetAddress().isEmpty()) {
            return false;
        }

        if (value.getPinCode().length() < 6) {
            return false;
        }

        if (value.getCountry().length() < 4) {
            return false;
        }

        return true;
    }
}

13.3. Validation Configuration

You can configure bean validation using XML descriptors in the validation.xml file located in the /META-INF directory. If this file exists in the class path, its configuration is applied when the ValidatorFactory gets created.

Example: Validation Configuration File

The following example shows several configuration options of the validation.xml file. All the settings are optional. These options can also be configured using the javax.validation package.

<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>
        org.hibernate.validator.HibernateValidator
    </default-provider>
    <message-interpolator>
        org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator
    </message-interpolator>
    <constraint-validator-factory>
        org.hibernate.validator.engine.ConstraintValidatorFactoryImpl
    </constraint-validator-factory>

    <constraint-mapping>
        /constraints-example.xml
    </constraint-mapping>

    <property name="prop1">value1</property>
    <property name="prop2">value2</property>
</validation-config>

The node default-provider allows to choose the bean validation provider. This is useful if there is more than one provider on the classpath. The message-interpolator and constraint-validator-factory properties are used to customize the used implementations for the interfaces MessageInterpolator and ConstraintValidatorFactory, which are defined in the javax.validation package. The constraint-mapping element lists additional XML files containing the actual constraint configuration.