Summary of case

In this article, we introduce the basics of validating Java beans using a standard framework – JSR 380, also known as Bean Validation 2.0.

Of course, validating user input is a very common requirement in most applications, and the Java Bean Validation framework has become the de facto standard for handling this logic.

JSR 380

JSR 380 is the specification of the Java API for bean validation, part of JavaEE and JavaSE, which uses annotations such as @notnull, @min, and @max to ensure that bean properties meet certain criteria.

This version requires Java 8 or later and takes advantage of new features added in Java 8, such as type annotations, and support for new types such as Optional and LocalDate.

For complete information on the specification, continue to read JSR 380.

dependency

We’ll use Maven examples to show the required dependencies, but of course you can add these jars in various ways.

Validation of the API

According to the JSR 380 specification, validation-API dependencies contain the standard validation API:

<dependency>
    <groupId>javax.validation</groupId>
    <artifactId>validation-api</artifactId>
    <version>2.0.0. The Final</version>
</dependency>
Copy the code

Verify the API reference implementation

Hibernate Validator is a reference implementation of the validation API.

To use it, we must add the following dependencies:

<dependency>
    <groupId>org.hibernate.validator</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>6.0.2. The Final</version>
</dependency>
<dependency>
    <groupId>org.hibernate.validator</groupId>
    <artifactId>hibernate-validator-annotation-processor</artifactId>
    <version>6.0.2. The Final</version>
</dependency>
Copy the code

A quick note here is that hibernate-Validator is completely independent of Hibernate’s persistence aspects, and by adding them as dependencies, we don’t add those persistence aspects to the project.

Expression language dependencies

JSR 380 provides support for variable interpolation, allowing expressions to be used in violation messages.

To parse these expressions, we must add dependencies to the expression language API and the IMPLEMENTATION of that API. GlassFish provides a reference implementation:

<dependency>
    <groupId>javax.el</groupId>
    <artifactId>javax.el-api</artifactId>
    <version>3.0.0</version>
</dependency>
 
<dependency>
    <groupId>org.glassfish.web</groupId>
    <artifactId>javax.el</artifactId>
    <version>2.2.6</version>
</dependency>
Copy the code

If these jars are not added, you will receive an error message at run time, as follows:

HV000183: unable to load ‘javax.mail. El. ExpressionFactory’. Check whether you have EL in the classpath dependencies, or use ParameterMessageInterpolator

Use validation annotations

We’ll use the User bean as the primary example here and add some simple validation to it:

import javax.validation.constraints.AssertTrue;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import javax.validation.constraints.Email;
 
public class User {
 
    @NotNull(message = "Name cannot be null")
    private String name;
 
    @AssertTrue
    private boolean working;
 
    @Size(min = 10, max = 200, message 
      = "About Me must be between 10 and 200 characters")
    private String aboutMe;
 
    @Min(value = 18, message = "Age should not be less than 18")
    @Max(value = 150, message = "Age should not be greater than 150")
    private int age;
 
    @Email(message = "Email should be valid")
    private String email;
 
    // standard setters and getters 
}
Copy the code

All the annotations used in the example are standard JSR annotations:

  • @notnull – verifies that annotated property values are NotNull
  • @assertTrue – Verifies that the annotated property value is true
  • @size – Verifies that the annotated attribute value has a Size between the attribute min and Max; Can be applied to String, Collection, Map, and array properties
  • @min – Verifies that the value of the annotated property is less than the value property
  • @max – Verifies that the value of the annotated property is greater than the value property
  • @email – Verifies that the annotated property is a valid Email address

Some annotations accept other attributes, but the Message attribute is common to all attributes. This is the message that is typically rendered when the value of the corresponding attribute is not validated.

Some other comments that can be found in JSR are:

  • @notempty – Verifies that the property is not null or null; Can be applied to String, Collection, Map, or Array values
  • @notblank – Applies only to text values and verifies that the property is not NULL or a space
  • @positive and @positiveorZero – Applies to values and verifies whether they are strictly Positive or Positive, including 0
  • @Negative and @NegativeOrZero – applies to values and verifies whether they are strictly Negative or Negative, including 0
  • @past and @PastorPresent – Verifies whether the date value is Past, including the present; You can apply to date types, including those added in Java 8
  • @Future and @FutureOrPresent – Verifies whether the date value will include the present in the Future

Validation comments can also be applied to elements of a collection:

List<@NotBlank String> preferences;
Copy the code

In this case, validate any value added to the list of options.

The specification also supports new Optional types in Java 8:

private LocalDate dateOfBirth;
 
public Optional<@Past LocalDate> getDateOfBirth() {
    return Optional.of(dateOfBirth);
}
Copy the code

Here, the validation framework automatically unpacks the LocalDate value and validates it.

Program verification

Some frameworks – such as Spring- use annotations to trigger validation in a simple way. This is mainly so that we don’t have to interact with the program validation API.

Now let’s go to the manual path and set it up programmatically:

ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
Copy the code

To validate the bean, we must first have a Validator object, which uses the ValidatorFactory construct.

Define the Bean

We now want to set an invalid user – using an empty name value:

User user = new User();
user.setWorking(true);
user.setAboutMe("Its all about me!");
user.setAge(50);
Copy the code

Verify the Bean

Now that we have a Validator, we can validate our bean by passing it to the Validate method. Any violation of the constraints defined in the User object is returned as a Set.

Set<ConstraintViolation<User>> violations = validator.validate(user);
Copy the code

By iterating over violations, we can use the getMessage method to get all violation messages.

for (ConstraintViolation<User> violation : violations) {
    log.error(violation.getMessage()); 
}
Copy the code

In our example (ifNameIsNull_nameValidationFails), this collection will contain a ConstraintViolation, with the message “Name not NULL”.

Conclusion the case

This article focuses on the simple delivery of the standard Java Validation API and illustrates the basics of bean Validation using javax.Validation annotations and apis.