+

Search Tips   |   Advanced Search

Bean validation in JPA

The Java Persistence API (JPA) 2.0 provides support for the Bean Validation API so that data validation can be done at run time. This topic includes a usage scenario where bean validation is used in the JPA environment of a sample digital image gallery application.

The Bean Validation API provides validation across technologies on Java EE 6 and JSE environments. In addition to JPA 2.0, these technologies include JSF 2.0 and JCA 1.6.

There are three core concepts of bean validation:

If we are running applications in an integrated environment like JPA, there is no need to interface directly with the validator.

Validation constraints are annotations or XML code added to a class, field, or method of a JavaBeans component, and used to define regular constraint definitions, and for composing constraints. The built-in constraints are defined by the bean validation specification and are available with every validation provider.


Constraints and JPA

The following usage scenario illustrates how a built-in constraint is used in the JPA architecture of a sample digital image gallery application.

In the first code example, a built-in constraint is added to a simple entity of the JPA model called image. An image has an ID, image type, file name, and image data. The image type must be specified and the image file name must include a valid JPEG or GIF extension. The code shows the annotated image entity with some built-in bean validation constraints applied.

The Image class uses two built-in constraints, @NotNull and @Pattern. The @NotNull constraint ensures that an ImageType element is specified and the @Pattern constraint uses regular expression pattern matching to ensure that the image file name is suffixed with a supported image format. Each constraint has corresponding validation logic that gets started at run time when the image entity is validated. If either constraint is not met, the JPA provider throws a ConstraintViolationException with the defined message. The JSR-303 specification also makes provisions for the use of a variable within the message attribute. The variable references a keyed message in a resource bundle. The resource bundle supports environment-specific messages and globalization, translation, and multicultural support of messages.

We can create our own custom validator and constraints. In the previous example, the Image entity used the @Pattern constraint to validate the file name of the image. However, it did not check constraints on the actual image data itself. We can use a pattern-based constraint; however, we do not have the flexibility that you would if created a constraint specifically for checking constraints on the data. In this case we can build a custom method-level constraint annotation. The following is a custom or user-defined constraint called ImageContent.

Next, create the validator class, ImageContentValidator. The logic within this validator gets implemented by the validation provider when the constraint is validated. The validator class is bound to the constraint annotation through the validatedBy attribute on the @Constraint annotation as shown in the following code:

Apply this new constraint to the getData() method on the Image class; for example:

When validation of the data attribute occurs, the isValid() method in the ImageContentValidator is started. This method contains logic for performing simple validation of the format of the binary image data. A potentially overlooked feature in the ImageContentValidator is that it can also validate for a specific image type. By definition, it accepts JPEG or GIF formats, but it can also validate for a specific format. For example, by changing the annotation to the following code example, the validator is instructed to only permit image data with valid JPEG content:

Type-level constraints are also a consideration because we might need to validate combinations of attributes on an entity. In the previous examples validation constraints were used on individual attributes. Type-level constraints make it possible to provide collective validation. For example, the constraints applied to the image entity validate that an image type is set (not null), the extension on the image file name is of a supported type, and the data format is correct for the indicated type. But, for example, it does not collectively validate that a file named img0.gif is of type GIF and the format of the data is for a valid GIF file image. For more information about type-level constraints, see the white paper, OpenJPA Bean Validation Primer, and the section "Type-level constraints."


Validation groups

Bean validation uses validation groups to determine what type of validation and when validation occurs.

There are no special interfaces to implement or annotations to apply to create a validation group. A validation group is denoted by a class definition.

Best practice: When using groups, use simple interfaces. Using a simple interface makes validation groups more usable in multiple environments. Whereas, if a class or entity definition is used as a validation group, it might pollute the object model of another application by bringing in domain classes and logic that do no make sense for the application. By default, if a validation group or multiple groups is not specified on an individual constraint, it is validated using the javax.validation.groups.Default group. Creating a custom group is as simple as creating a new interface definition. bprac

For more information about validation groups, read the white paper, OpenJPA Bean Validation Primer, and the section "Validation groups."


JPA domain model

In addition to the Image entity are Album, Creator and Location persistent types. An Album entity contains a reference to collection of its Image entities. The Creator entity contains a reference to the album entities that the image Creator contributed to and a reference to the Image entities created. This provides full navigational capabilities to and from each of the entities in the domain. An embeddable location, has been added to image to support storing location information with the image.

The Album and Creator entities have standard built-in constraints. The embeddable location is more unique in that it demonstrates the use of the @Valid annotation to validate embedded objects. To embed location into an image, a new field and corresponding persistent properties are added to the Image class; for example:

The @Valid annotation provides chained validation of embeddable objects within a JPA environment. Therefore, when image is validated, any constraints on the location it references are also validated. If @Valid is not specified, the location is not validated. In a JPA environment, chained validation through @Valid is only available for embeddable objects. Referenced entities and collections of entities are validated separately to prevent circular validation.


Bean validation and the JPA environment

The JPA 2.0 specification makes integration with the Bean Validation API simple. In a JSE environment, bean validation is enabled by default when you provide the Bean Validation API and a bean validation provider on the runtime class path. In a Java EE 6 environment, the application server includes a bean validation provider so there is no need to bundle one with the application. In both environments, use a Version 2.0 persistence.xml file.

A Version 1.0 persistence.xml provides no means to configure bean validation. Requiring a Version 2.0 persistence.xml prevents a pure JPA 1.0 application from incurring the validation startup and runtime costs. This is important given that there is no standard means for a 1.0-based application to disable validation. In a Java EE 6 environment, enable validation in an existing 1.0 application by modifying the root element of the persistence.xml file. The following example represents the persistence.xml file:

Bean validation provides three modes of operation within the JPA environment:

Auto mode simplifies deployment, but can lead to problems if validation does not take place because of a configuration problem.

Best practice: Use either none or callback mode explicitly for consistent behavior.bprac Also, if none is specified, JPA optimizes at startup and does not attempt to perform unexpected validation. Explicitly disabling validation is especially important in a Java EE 6 environment where the container is mandated to provide a validation provider. Therefore, unless specified, a JPA 2.0 application started in a container has validation enabled. This process adds additional processing during life cycle events.

There are two ways to configure validation modes in JPA 2.0. The simplest way is to add a validation-mode element to the persistence.xml with the wanted validation mode as shown in the following example:

The other way is to configure the validation mode programmatically by specifying the javax.persistence.validation.mode property with value auto, callback, or none when creating a new JPA entity manager factory as shown in the following example:

Bean validation within JPA occurs during JPA life cycle event processing. If enabled, validation occurs at the final stage of the PrePersist, PreUpdate, and PreRemove life cycle events. Validation occurs only after all user-defined life cycle events, since some of those events can modify the entity that is being validated. By default, JPA enables validation for the default validation group for PrePersist and PreUpdate life cycle events. If we must validate other validation groups or enable validation for the PreRemove event, we can specify the validation groups to validate each life cycle event in the persistence.xml as shown in the following example:

The following example shows various stages of the JPA life cycle, including persist, update, and remove:


Exceptions

Validation errors can occur in any part of JPA life cycle.

If one or more constraints fail to validate during a life cycle event, a ConstraintViolationException is thrown by the JPA provider. The ConstraintViolationException thrown by the JPA provider includes a set of ConstraintViolations that occurred. Individual constraint violations contain information regarding the constraint, including: a message, the root bean or JPA entity, the leaf bean which is useful when validating JPA embeddable objects, the attribute which failed to validate, and the value that caused the failure. The following is a sample exception handling routine:

Constraint violation processing is typically simple when using attribute-level constraints. For a type-level validator with type-level constraints, it can be more difficult to determine which attribute or combination of attributes failed to validate. Also, the entire object is returned as the invalid value instead of an individual attribute. In cases where specific failure information is required, use of an attribute-level constraint or a custom constraint violation might be provided as described in the Bean Validation specification.


Sample

The JPA model and image gallery application usage scenario provided in this topic can be implemented through a sample provided in the white paper, OpenJPA Bean Validation primer.


Related concepts

JCA 1.6 support for annotations in RAR modules
  • Bean validation in RAR modules
  • Bean Validation
  • Migration of JPA applications and bean validation
  • Task overview: Store and retrieve persistent data with the JPA API Bean validation troubleshooting tips
  • Bean validation built-in constraints
    OpenJPA Bean Validation Primer
    JSR 303: Bean Validation
  • Troubleshooting bean validation in RAR modules