Chapter 10. Bean Validation

Barbara Liskov and Stephen Zilles (Abstract Data Types, 1974) said, "Some of the operations in the cluster for that "type" are polymorphic; the operations mays be defined over many type domains, subject to the constraint that the types of any given argument set are type-consistent."

In object oriented programming, we are mostly familiar with value objects, which are types that have encapsulation of data and accessibility operators. Value objects generally do not have business rules, or e-commerce entity complex behavior, and thus they are represented as Plain-Old-Java-Objects (POJOs). The way developers write JavaBeans now means value objects in Java are basic Java Beans.

So why is there all the fuss over these value objects? Values objects are often validated in the application. In our business applications, we developers habitually write lots of boilerplate code that sanity checks the properties of value objects. We check if a particular field or property is null or not null, if the property is the correct type, whether it can be an empty string or not, if the property is a decimal, floating-point or an integer, or even whether a property's value fits in a bounded range of values. To add insult to injury, we then also write more of the same user-defined validation checking code in our web applications and in the presentation tier. Our lack of reuse and regretful duplication of code is complete in this challenge when our value objects are marshaled as persistence capable objects, because we repeat ourselves with the similar validation code before saving or updating it to the database.

Unfortunately this validation code is repeated in different tiers of the application; the code is not universal or shared or specific to the application, and more often than not mistakes will exist in the checking. This leads to inconsistencies of validation within an application. Well, Java EE 7 has a standard solution, which is called Bean Validation.

Introduction to Bean Validation

The focus of Bean Validation API 1.1 is ease-of-use. The expert group designed the update so that developers can apply a single constraint for multiple layers of their applications. These constraints can be applied at the presentation layer on web frameworks such as JavaServer Faces and Apache WebWork, at the business layer where your logic works, and of course the data storage layer. With Bean Validation, developers need to define the constraints only once, and then inside the application you invoke the validation anywhere you want to check.

For Java EE 7 application servers, Bean Validation can be automatically applied to persistence capable object, which means JPA gets constraint validation for free. For web frameworks running under the Java EE 7 Web Profile, Bean Validation can also be automatically applied to JSF when there is an HTTP request sent to the web layer as the request is mapped to Managed Beans.

The Bean Validation framework is usable outside of Java EE standard as well. The reference implementation to the Bean Validation has integration with other frameworks such as GWT, Wicket, and Tapestry. The Spring Framework, since version 3.1, also has an integration module to the previous Bean Validation implementation, version 1.0.

New features in 1.1

Bean Validation 1.1 specification introduces several new features:

  • It provides better integration with CDI, which has a few components to all injections of custom validators into your application.
  • It adds new kinds of factories—providers and resolvers—to allow the developer to customize the validation.
  • Developers can write constraints on parameters and return values of arbitrary methods and constructors. This feature is called method validation, and it permits the declarative validation of methods with pre and post-conditions.
  • Constraint validation messages can now be properly internationalized for other languages and locale with string formatting.
  • Bean Validation 1.1 now integrates and uses the EL 3.0, the standard Expression Language JSR 341 standard.

The expert group has really attempted to make our engineering working livesmuch better.

Tip

XSS Cross-Site Scripting

Cross-Site Scripting ( XSS ) is the term for client-side hacking of web applications to exploit flaws in the implementation logic where there is lack of validation, weak security, and advantage to be gained, including manipulating system credentials in to order to become an authorized administrator or super user. XSS enables attackers to inject unauthorized observer scripts into the application and thereby gain administrative privileges in web pages viewed by other legitimate users. Fortunately, Java is static compiled, but direct SQL and dynamic languages such as PHP, Ruby and Groovy are prone to scripting attacks, if they are not protected from malicious evolutions.

Bean Validation 1.1 can help with a standard validation on value objects and persistence capable objects. It is worth following the advice of the XSS Prevent Cheat Sheet https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheetand also using an additional Java prevention framework such as Coverity Security Library https://github.com/coverity/coverity-security-library .

Let's move on to a simple example of Bean Validation.

A quick example

Bean Validation takes advantage of annotations, which specify how to verify the constraints on a value object. The constraints can be found under the Java package name javax.validation.constraints.

The reference implementation for Bean Validator 1.1 is the open source framework Hibernate Validator, which is the reference implementation of the specification. The website http://beanvalidation.org is the standard location for the current and previous specifications.

An example of value object that is annotated with constraints is as follows:

public final class Person {
    @NotNull
    private final String firstName;
    @NotNull
    private final String lastName;

    @Min(18) @Max(65)
    private int age;

    public Person(final String firstName,
        final String lastName, final int age) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
    }

public String getFirstName() {return firstName; }    
public String getLastName() {return lastName; }
    public int getAge() { return age; }
}

The Person class is an immutable value object. It is thread-safe because the state cannot be altered, this reference does not escape the constructor, and all properties are marked as final and are fully initialized in the constructor, but that is beside the point.

A quick example

The properties firstName and lastName are marked with the @NotNull, which declares a constraint to the class member to ensure that the value is not null.

The property age is marked with the two annotations @Min and @Max, which declares two constraints for a numeric field with the value. In UK English, this says the person's age must be an adult and not retired (the male pension age is currently still 65 years in Great Britain in 2013).

Let's write a simple unit test to verify these constraints with Hibernate Validator framework:

package je7hb.beanvalidation.essentials;
import static org.junit.Assert.*;
import org.junit.*;
import javax.validation.*
import java.util.Set;

public class PersonValidatorTest {
    private static Validator validator;

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

    @Test
    public void validatePerson() {
        Person person = new Person("Sazanne", "Abdiman", 34 );
        Set<ConstraintViolation<Person>> constraintViolations
      = validator.validate(person);
        assertEquals(0, constraintViolations.size());
    }

    @Test
    public void validatePersonMissingFirstName() {
        Person person = new Person(null, "Abdiman", 34 );
        Set<ConstraintViolation<Person>> constraintViolations
      = validator.validate(person);
        assertEquals(1, constraintViolations.size());
    }
    @Test
    public void validatePersonMissingWrongAge() {
        Person person = new Person("Kieran", "Abdiman", 16 );
        Set<ConstraintViolation<Person>> constraintViolations
      = validator.validate(person);
        assertEquals(1, constraintViolations.size());
    }
}

This unit test PersonValidatorTest verifies the constraints applied to the value object. In the @BeforeClass static method setUp(), we create a bean validator using a factory. The class javax.validation.ValidatorFactory in the API allows an application to retrieve the default validator, which is a type of javax.validation.Validator.

Once we have the validator in a static member of the test, we write the test methods. We first create a value object in each test, and then invoke the validator's validate() method, which returns a set collection of javax.validation.ConstraintViolation objects. We check the size of the set collection to verify the tests. (Obviously for full acceptance criteria and pedantic behavioral-driven Design we would write more tests for full compliance.) If the set collection is empty and the size of violations is zero then the object is valid and has passed the validator.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.128.173.53