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:
Constraint | Description |
---|---|
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, Min | The specified value has to be greater than or lower than the specified value. |
Null, NotNull | The specified element must be null or not null. |
Pattern | The specified element’s value should match the given pattern. |
Digits | The specified element’s value must has value within the accepted range. |
Size | The 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.