Hibernate Validator

In this tutorial, we show how to validate data with Hibernate validator. Validating input received from the user to maintain data integrity is an important part of application logic. Validation is incorporated in Java web frameworks such as Stripes, Ninja framework, or Play framework.

Bean validation

Bean Validation is a validation model introduced in Java EE 6 platform. The Bean Validation model is supported by constraints in the form of annotations placed on a field, method, or class of a JavaBeans component. It is also possible to use XML validation descriptors.

Hibernate validator definition

Hibernate Validator is the reference implementation of Bean Validation. Hibernate Validator allows to express and validate application constraints. The default metadata source are annotations, with the ability to override and extend through the use of XML. It is not tied to a specific application tier or programming model and is available for both server and client application programming.

Hibernate validator command line application

In the following example, we use the Hibernate Validator in a simple command line application.

pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.zetcode</groupId>
    <artifactId>HibernateValidation</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>
    
    <dependencies>
        <dependency>
            <groupId>javax.el</groupId>
            <artifactId>javax.el-api</artifactId>
            <version>2.2.4</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish.web</groupId>
            <artifactId>javax.el</artifactId>
            <version>2.2.4</version>
        </dependency>

        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator-cdi</artifactId>
            <version>5.2.4.Final</version>
        </dependency>
        
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.8</version>
            <scope>provided</scope>
        </dependency>        
        
    </dependencies>
    
</project>

The Maven pom.xml contains dependencies for the Hibernate Validator and for the Lombok library. The Lombok is used to reduce some boilerplate.

Car.java
package com.zetcode.bean;

import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import lombok.Data;

@Data
public class Car {
    
    private Long Id;
    
    @NotNull
    @Size(min=4, max=50)
    private String name;
        
    @Min(value = 1000)
    @Max(value = 5000000, message="There is no such expensive car")
    private int price;
    
    public Car() {}
    
    public Car(String name, int price) {
        
        this.name = name;
        this.price = price;
    } 
}

We have a Car bean where we validate data.

@Data
public class Car {

The Car bean is decorated with the lombok's @Data annotation. It automatically creates the getter and setter methods, equals() method, toString() method, and hashCode() method.

@NotNull
@Size(min=4, max=50)
private String name;

The @NotNull annotation says that the name property may not be null. The @Size annotation sets the minimum and maximum size for the property.

@Min(value = 1000)
@Max(value = 5000000, message="There is no such expensive car")
private int price;

The @Min constraint sets the minimum value for the price property. The message element is used to create the error message.

ClientApp.java
package com.zetcode.client;

import com.zetcode.bean.Car;
import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;

public class ClientApp {

    private static Validator validator;

    public static void main(String[] args) {

        Car car1 = new Car("Volvo", 29000);
        Car car2 = new Car("Skoda", 900);
        Car car3 = new Car(null, 29000);
        Car car4 = new Car("Cit", 21000);
        Car car5 = new Car("Bentley", 8000000);

        ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        validator = factory.getValidator();
        
        validate(car1);
        validate(car2);
        validate(car3);
        validate(car4);
        validate(car5);        
    }

    public static void validate(Car car) {

        Set<ConstraintViolation<Car>> cvs = validator.validate(car);

        for (ConstraintViolation<Car> cv : cvs) {
            System.out.println(cv.getPropertyPath() + ": " + cv.getMessage());
        }        
    }
}

In the client application, we create five car objects and validate them.

Car car1 = new Car("Volvo", 29000);
Car car2 = new Car("Skoda", 900);
Car car3 = new Car(null, 29000);
Car car4 = new Car("Cit", 21000);
Car car5 = new Car("Bentley", 8000000);

Five car objects are created. Four cars have values that do not pass the validation process. For example, the price of the Skoda car is too low; i.e. below the minimum 1000 value.

ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
validator = factory.getValidator();

A validation factory is used with the buildDefaultValidatorFactory() method. From the factory, we get the validator with the getValidator() method. It is recommended to cache the validator factory because it is expensive to create.

Set<ConstraintViolation<Car>> cvs = validator.validate(car);

A car is validated using the validator's validate() method.

for (ConstraintViolation<Car> cv : cvs) {
    System.out.println(cv.getPropertyPath() + ": " + cv.getMessage());
}

We print the error messages for constraint violations.

price: must be greater than or equal to 1000
name: may not be null
name: size must be between 4 and 50
price: There is no such expensive car

When running the application, we receive these error messages.

Hibernate validator web application

In the second example, we utilize Hibernate Validator in a web application. The application is deployed on Apache Tomcat server. The sources for this application are available at author's Github repository.

Project structure
Figure: Project structure

The figure shows the project structure in NetBeans.

context.xml
<?xml version="1.0" encoding="UTF-8"?>
<Context path="/HibernateValidation"/>

The context.xml file contains the context path of the application.

pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>HibernateValidation2</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <name>HibernateValidation2</name>

 
    <dependencies>

        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-web-api</artifactId>
            <version>7.0</version>
            <scope>provided</scope>
        </dependency>
        
        <dependency>
            <groupId>jstl</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        
        <dependency>
            <groupId>javax.el</groupId>
            <artifactId>javax.el-api</artifactId>
            <version>2.2.4</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish.web</groupId>
            <artifactId>javax.el</artifactId>
            <version>2.2.4</version>
        </dependency>

        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator-cdi</artifactId>
            <version>5.2.4.Final</version>
        </dependency>        
        
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.8</version>
            <scope>provided</scope>
        </dependency>           
                        
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>

                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.3</version>
                <configuration>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

The Maven pom.xml contains dependencies for the Java EE Web API, Hibernate Validator, and for the Lombok library.

index.jsp
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Validation</title>
    </head>
    <body>

        <p>
            Enter your name and email:
        </p>

        <form method="post" action="Greet">

            Name: <input type="text" name="username"> <br>
            Email: <input type="text" name="email"> <br>

            <input type="submit" value="Submit"> 

        </form>


    </body>
</html>

The index.jsp is the entry point to our application. It contains a HTML form with two fields: username and email. The values entered into these fields are going to be validated by the application.

<form method="post" action="Greet">
...
</form>

Upon submitting the form, the Greet servlet is invoked.

hello.jsp
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Greeting</title>
    </head>
    <body>
        Hello <c:out value="${param.username}"/>! <br>
        Your email is <c:out value="${param.email}"/>.
    </body>
</html>

When the input data passes the validation test, the hello.jsp page is displayed. It displays the entered data.

valError.jsp
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Error</title>
    </head>
    <body>
        <p>
            <c:forEach var="err" items="${errMsg}">
                <c:out value="${err}"/>
                <br>
            </c:forEach>
        </p>
    </body>
</html>

If the validation fails, the valError.jsp is displayed. It shows the error messages stored in the errMsg attribute. The attribute is set during the validation process.

User.java
package com.zetcode.bean;

import javax.validation.constraints.Pattern;
import lombok.Data;
import org.hibernate.validator.constraints.NotEmpty;

@Data
public class User {
    
    @NotEmpty
    private String name;
    
    @NotEmpty
    @Pattern(regexp="^[a-zA-Z0-9._-]+@[a-zA-Z0-9-]+\\.[a-zA-Z.]{2,5}", 
            message="Please provide a valid email address")    
    private String email;
}

The User bean is decorated with Lombok and Hibernate Validator annotations.

@NotEmpty
private String name;

The @NotEmpty annotation causes that the user name may not be empty.

@NotEmpty
@Pattern(regexp="^[a-zA-Z0-9._-]+@[a-zA-Z0-9-]+\\.[a-zA-Z.]{2,5}", 
        message="Please provide a valid email address")    
private String email;

The email may not be empty and must match the given patter. The pattern is set with the @Pattern annotation.

DoValidate.java
package com.zetcode.util;

import com.zetcode.bean.User;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;

public class DoValidate {

    public static  List<String> validate(User user) {

        List<String> errors = new ArrayList();
        
        ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        Validator validator = factory.getValidator();

        Set<ConstraintViolation<User>> cvs = validator.validate(user);

        if (!cvs.isEmpty()) {

            for (ConstraintViolation<User> cv : cvs) {

                StringBuilder err = new StringBuilder();
                err.append(cv.getPropertyPath());
                err.append(" ");
                err.append(cv.getMessage());
                errors.add(err.toString());
            }
        }
        
        return errors;
    }
}

The validation is performed in the DoValidate utility class.

if (!cvs.isEmpty()) {

    for (ConstraintViolation<User> cv : cvs) {

        StringBuilder err = new StringBuilder();
        err.append(cv.getPropertyPath());
        err.append(" ");
        err.append(cv.getMessage());
        errors.add(err.toString());
    }
}

When there are constraint violations, we create a list of error messages. The getMessage() method gets the error message of the constraint violation.

return errors;

The list of error messages are returned to the caller. The list is empty if no violations were detected.

Greeting.java
package com.zetcode.web;

import com.zetcode.bean.User;
import com.zetcode.util.DoValidate;
import java.io.IOException;
import java.util.List;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(name = "Greeting", urlPatterns = {"/Greet"})
public class Greeting extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest request, 
            HttpServletResponse response) 
            throws ServletException, IOException {
        
        response.setContentType("text/html;charset=UTF-8");

        String page = "/hello.jsp";
        
        String username = request.getParameter("username");
        String email = request.getParameter("email");

        User user = new User();
        user.setName(username);
        user.setEmail(email);

        List<String> errors = DoValidate.validate(user);

        if (!errors.isEmpty()) {

            request.setAttribute("errMsg", errors);

            page = "/valError.jsp";

        } else {

            request.setAttribute("user", user);
        }

        RequestDispatcher disp = getServletContext().getRequestDispatcher(page);
        disp.forward(request, response);
    }
}

The Greeting servlet retrieves the request data and calls the DoValidate.validate() utility method. Depending on the outcome of the validation, the servlet dispatches to the hello.jsp or valError.jsp pages.

Error message
Figure: Error message

The application responds with an error message if the email has an incorrect format.

This was the validation filter tutorial. We have built a console and a web application using Hibernate Validator, JSTL, JSP, Apache Tomcat, and Maven. You might also want to check some related tutorials: Java validation filter tutorial, Java tutorial, or Stripes tutorial.