2010-07-20

Bean Validation with JEE 6 (JSR-303)

In this article I will show you some basic Bean Validation examples. You may want to (you should) read the official JSR 303 document to learn more. First, a quote from that document.

Validating data is a common task that occurs throughout an application, from the presentation layer to the persistence layer. Often the same validation logic is implemented in each layer, proving to be time consuming and errorprone. To avoid duplication of these validations in each layer, developers often bundle validation logic directly into the domain model, cluttering domain classes with validation code that is, in fact, metadata about the class itself.

This JSR defines a metadata model and API for JavaBean validation. The default metadata source is annotations, with the ability to override and extend the meta-data through the use of XML validation descriptors.



Built-in constraints


To use built-in constraints your project must import the javax.validation dependency. Maven:

   <dependency>
       <groupId>javax.validation</groupId>
       <artifactId>validation-api</artifactId>
       <version>1.0.0.GA</version>
       <type>jar</type>
       <scope>test</scope>
   </dependency>

Here are some built-in annotations:
  • @Null
  • @NotNull
  • @AssertTrue
  • @AssertFalse
  • @Min
  • @Max
  • @DecimalMin
  • @DecimalMax
  • @Size - covers min and max
  • @Digits
  • @Past - must be a date in the past
  • @Future - must be a date in the future
  • @Pattern

Usage:
import javax.validation.constraints.Size;
import javax.validation.constraints.NotNull;

  // ...
  @NotNull
  @Size(min = 3)
  public String getName() {
   return name;
  }
UPDATE: @Min is for numbers only, my bad. This code now uses @Size.

Testing the validation


Here’s an example of unit testing constraints. You must add a Bean Validation implementation:
   <dependency>
       <groupId>org.hibernate</groupId>
       <artifactId>hibernate-validator</artifactId>
       <version>4.0.2.GA</version>
       <type>jar</type>
       <scope>test</scope>
   </dependency>

And the code itself:
package me.m1key.jsf;

import static org.junit.Assert.assertEquals;

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;

public class DogsBeanTest {
  private static Validator validator;

  @BeforeClass
  public static void setUp() {
   ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
   validator = factory.getValidator();
  }

  @Test
  public void test() {
   DogsBean bean = new DogsBean();

   Set<ConstraintViolation<DogsBean>> constraintViolations = validator
           .validate(bean);
   assertEquals(1, constraintViolations.size());
  }

}
It could be a lot better, because I only check the size of the violations set here. You might check the actual error message (still not so elegant...).


Error messages


Error messages are customizable. They can be modified if you provide a ResourceBundle called ValidationMessages (so, you can create a ValidationMessages .properties file and make if available in the classpath root).


When does validation occur?


Very good question! The specification doesn’t explicitly say when; instead it provides a clue in form of Appendices D, E and F.

Different JEE technologies launch Bean Validation. But when?

JPA calls validation upon:
  • pre-persist
  • pre-update
  • pre-remove
And these are entity lifecycle events. See Section 3.6 of JSR 317 for more details.

JSF calls validation upon:
  • the process validation phase
See Section 2.5.7 of JSR 314 for more details.


Next article


In the next article I will show you how to define custom constraints and more.

1 comment: