Bean Validation 1.1 in Java EE 7 – Using Default Constraints

Bean Validation 1.1 (JSR 349) is integrated as part of Java EE 7. The new features of Bean Validation 1.1 are as follows:

  • Applying constraints on method parameters and return values. This can be used in creating a pre and post condition contract.
  • Constraints can be applied to constructors.
  • New API to obtain metadata of constraint and constraint objects.

What is Bean Validation?

Bean validation is an attempt to provide constructs for defining constraints for your data i.e Java beans by using inbuilt i.e default constraint rules and also by creating custom constraint rules. These constraints can be used to validate beans, attributes, constructors, method return types and parameters. There are numerous reference implementations available and Hibernate Validator provides support for the latest Bean Validation 1.1 specification.

also read:

In this post I will create a Java bean representing Book details like ISBN number, Title, Publication, Authors, Edition, Publication Date, Number of Pages, Cost and define constraints on these attributes using the default constraint rules provided by the Bean Validation reference implementation. The default constraints available are:

ConstraintDescription
AssertFalse
AssertTrue
The element should either be true or false.
DecimalMin
DecimalMax
The element should have a value greater than or lower than the specified value.
Future
Past
The date has to be in future
The date has to be in past.
Max, MinThe specified value has to be greater than or lower than the specified value.
Null, NotNullThe specified element must be null or not null.
PatternThe specified element’s value should match the given pattern.
DigitsThe specified element’s value must has value within the accepted range.
SizeThe specified element’s value’s size must be between the specified values.

Using Bean Validation constraints

The below Book Java Bean uses the Bean validation constraints:

import java.util.Date;
import java.util.List;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

public class Book {

  //The ISBN number cannot be null and should satisfy the given pattern.
  @NotNull
  @Pattern(regexp = "^(97(8|9))?\\d{9}(\\d|X)$")
  private String isbn;

  //There has to be atleast 1 author.
  @NotNull
  @Size(min = 1)
  private List<String> authors;

  //The book title should have atleast 10 characters and cannot be null.
  @NotNull
  @Size(min=10)
  private String title;

  //The book should have at least 50 pages.
  @Min(50)
  private int pages;

  //The book will be of atleast edition 1.
  @Min(1)
  private int edition;

  //The publisher name should be of atleast 5 characters and cannot be null.
  @NotNull
  @Size(min=5)
  private String publisher;

  //Cost cannot be null
  @NotNull
  private Double cost;

  //publication date cannot be null.
  @NotNull
  private Date publicationDate;

  public Book(String isbn,
          List<String> authors,
          String title,
          int pages,
          int edition,
          String publisher,
          Double cost,
          Date publicationDate) {

    this.isbn = isbn;
    this.authors = authors;
    this.title = title;
    this.pages = pages;
    this.edition = edition;
    this.publisher = publisher;
    this.cost = cost;
    this.publicationDate = publicationDate;

  }

  public String getIsbn() {
    return isbn;
  }

  public void setIsbn(String isbn) {
    this.isbn = isbn;
  }

  public List<String> getAuthors() {
    return authors;
  }

  public void setAuthors(List<String> authors) {
    this.authors = authors;
  }

  public String getTitle() {
    return title;
  }

  public void setTitle(String title) {
    this.title = title;
  }

  public int getPages() {
    return pages;
  }

  public void setPages(int pages) {
    this.pages = pages;
  }

  public int getEdition() {
    return edition;
  }

  public void setEdition(int edition) {
    this.edition = edition;
  }

  public String getPublisher() {
    return publisher;
  }

  public void setPublisher(String publisher) {
    this.publisher = publisher;
  }

  public Double getCost() {
    return cost;
  }

  public void setCost(Double cost) {
    this.cost = cost;
  }

  public Date getPublicationDate() {
    return publicationDate;
  }

  public void setPublicationDate(Date publicationDate) {
    this.publicationDate = publicationDate;
  }
}

And to see these constraints in action I have created a JUnit test which creates a Book instance and then updates the attributes with values which violate the constraint and then run the validator against the Book instance to identify and print the violations captured.

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
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.*;

public class BookTest {

  public BookTest() {
  }
  private static ValidatorFactory vf;
  private static Validator validator;
  private static Book book;

  @BeforeClass
  public static void setUpClass() {
    vf = Validation.buildDefaultValidatorFactory();
    validator = vf.getValidator();
    book = new Book("8125050515",
            Arrays.asList("Y. V. Reddy"),
            "SPECIFICATIONS OF ECONOMIC POLICIES AND INDIA'S REFORM AGENDA: NEW THINKING 1 EDITION",
            296, //number of pages
            1, //edition
            "Orient BlackSwan", //publisher
            310.0, //cost
            new Date());
  }

  /**
   * This should not report any validation errors.
   */
  @Test
  public void testNoValidationViolations() {
    System.out.println("*********No Validations Violation tests**************");
    identifyViolations(book, 0);
  }

  @Test
  public void testIsbnValidation() {
    System.out.println("*********ISBN Validation tests***************");
    String oldIsbn = book.getIsbn();
    book.setIsbn(null);
    identifyViolations(book, 1);

    //Some 9 characters string or invalid ISBN.
    book.setIsbn("812505051");
    identifyViolations(book, 1);

    //reset the ISBN value
    book.setIsbn(oldIsbn);
  }

  @Test
  public void testAuthorsValidation() {

    System.out.println("*********Authors Validation tests***************");

    List<String> oldAuthors = book.getAuthors();

    book.setAuthors(null);

    identifyViolations(book, 1);

    book.setAuthors(new ArrayList<String>());
    identifyViolations(book, 1);

    book.setAuthors(oldAuthors);

  }

  @Test
  public void testTitleValidation() {

    System.out.println("*********Title Validation tests***************");

    String oldTitle = book.getTitle();
    book.setTitle(null);
    identifyViolations(book, 1);

    book.setTitle("Small One");
    identifyViolations(book, 1);

    book.setTitle(oldTitle);
  }

  @Test
  public void testPagesValidation() {
    System.out.println("*********Page Count Validation tests***************");

    int oldPages = book.getPages();
    book.setPages(20);
    identifyViolations(book, 1);
    book.setPages(oldPages);
  }

  @Test
  public void testEditionValidation() {
    System.out.println("*********Edition Validation tests***************");

    int oldEdition = book.getEdition();
    book.setEdition(0);
    identifyViolations(book, 1);
    book.setEdition(oldEdition);
  }

  @Test
  public void testPublisherValidation() {
    System.out.println("*********Publisher Validation tests***************");

    String oldPublisher = book.getPublisher();
    book.setPublisher(null);
    identifyViolations(book, 1);

    book.setPublisher("Test");
    identifyViolations(book, 1);

    book.setPublisher(oldPublisher);

  }

  @Test
  public void testCostValidation() {
    System.out.println("*********Cost Validation tests***************");

    Double oldCost = book.getCost();

    book.setCost(null);
    identifyViolations(book, 1);
    book.setCost(oldCost);
  }
  @Test
  public void testPublicataionDateValidation() {
    System.out.println("*********Publication Date Validation tests***************");

    Date oldPublicationDate = book.getPublicationDate();
    book.setPublicationDate(null);
    identifyViolations(book, 1);
    book.setPublicationDate(oldPublicationDate);
  }
  private void identifyViolations(Book myBook,
          int expectedCountOfViolations) {

    Set<ConstraintViolation<Book>> violations = validator.validate(myBook);

    printErrors(violations);

    assertEquals(expectedCountOfViolations, violations.size());
  }

  private void printErrors(Set<ConstraintViolation<Book>> violations) {
    if (violations.isEmpty()) {
      System.out.println("No violations found!!!");
      return;
    }

    System.out.println("The following violations found: ");
    for (ConstraintViolation<Book> viol : violations) {
      System.out.println("Violation: " + viol.getMessage());
    }
  }
}

The output for the above JUnit test would be:

*********Authors Validation tests***************
The following violations found:
Violation: may not be null
The following violations found:
Violation: size must be between 1 and 2147483647
*********ISBN Validation tests***************
The following violations found:
Violation: may not be null
The following violations found:
Violation: size must be between 10 and 10
*********No Validations Violation tests**************
No violations found!!!
*********Title Validation tests***************
The following violations found:
Violation: may not be null
The following violations found:
Violation: size must be between 10 and 2147483647
*********Page Count Validation tests***************
The following violations found:
Violation: must be greater than or equal to 50
*********Edition Validation tests***************
The following violations found:
Violation: must be greater than or equal to 1
*********Publisher Validation tests***************
The following violations found:
Violation: may not be null
The following violations found:
Violation: size must be between 5 and 2147483647
*********Cost Validation tests***************
The following violations found:
Violation: may not be null
*********Publication Date Validation tests***************
The following violations found:
Violation: may not be null

As it is pretty straight forward to make use of the default constraints provided by Bean Validation API, I haven’t gone into detail on explaining the same. In the future post I will write about how one can create own constraints and use them as annotation to validate your business logic.

Comments

comments

About Mohamed Sanaulla

In his day job he works on developing enterprise applications using ADF. He is also the moderator of JavaRanch forums and an avid blogger.

Speak Your Mind

*