How to automatically validate entities with Hibernate Validator
Take your skills to the next level!
The Persistence Hub is the place to be for every Java developer. It gives you access to all my premium video courses, monthly Java Persistence News, monthly coding problems, and regular expert sessions.
Validation is an important task, but it’s most often also tedious to implement. It’s a good thing that the BeanValidation specification and Hibernate Validator as it’s reference implementation take over most of the work. They provide an easy to use, standardized way to validate object attributes and method parameters. And the best thing, they integrate with Hibernate ORM and all other JPA 2.x implementations to provide automatic validation of entity attributes.
Sounds interesting? Let me give you a quick overview of what you can do.
Add BeanValidation to your project
Hibernate and all other JPA 2.x implementations use BeanValidation by default. You just have to add it to the classpath of your application. The following code snippet shows the maven dependency for Hibernate Validator, the BeanValidation reference implementation. It transitively also adds the BeanValidation API.
<dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>5.3.4.Final</version> </dependency>
Hibernate Validator also requires an implementation of the Unified Expression Language (JSR 341). Java EE containers provide this dependency by default. In a Java SE environment, you need to add it yourself.
<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>
Define the Validation
The BeanValidation specification defines a set of annotations which you can use to perform standard validations on your entity attributes. You can also provide your own validation rules. Please have a look at the JavaDoc and the BeanValidation specification to learn more about standard and custom validation rules.
In this example, I use 2 of the standard annotations:
- @NotNull validates that an attribute is not null.
- @Size checks that the size of a CharSequence, Collection, Map or Collection is between the given min and max boundaries.
As you can see in the following code snippet, I annotated the title attribute of the Book entity with these 2 annotations. Each Book entity has to have a title that is not null and between 5 and 20 characters long.
@Entity public class Book implements Serializable { @Column @NotNull @Size(min=5, max=20) private String title; … }
Automatic Validation upon Lifecycle Events
The validation gets automatically executed when Hibernate, or any other JPA implementation, triggers a pre-persist, pre-update or pre-remove lifecycle events. The pre-persist and pre-update events trigger the validation of the default validation group which contains all validation constraints. Pre-remove lifecycle events trigger the validation of no validation group.
You can change this default behavior in the persistence.xml file by using the following properties to define the groups which shall be validated for each lifecycle event:
- javax.persistence.validation.group.pre-persist
- javax.persistence.validation.group.pre-update
- javax.persistence.validation.group.pre-remove
Example
Let’s have a look at an example that tries to persist an invalid entity. I annotated the title attribute of the Book entity with @NotNull and @Size(min=5, max=20). When I try to persist a new Book entity without setting a title attribute, Hibernate will use Hibernate Validator as a BeanValidation implementation to validate the title attribute and throw a ValidationConstraintException.
EntityManager em = emf.createEntityManager(); em.getTransaction().begin(); Book b = new Book(); em.persist(b); try { em.getTransaction().commit(); Assert.fail(“ConstraintViolationException exptected”); } catch (RollbackException e) { Set<ConstraintViolation<?>> violations = ((ConstraintViolationException)e.getCause()).getConstraintViolations(); for (ConstraintViolation v : violations) { log.info(v); } } em.close();
As you can see in the following log messages, Hibernate triggered the validation before it persisted the entity and the validation failed.
18:21:33,229 ERROR ExceptionMapperStandardImpl:39 – HHH000346: Error during managed flush [Validation failed for classes [org.thoughts.on.java.model.Book] during persist time for groups [javax.validation.groups.Default, ] List of constraint violations:[ConstraintViolationImpl{interpolatedMessage=’may not be null’, propertyPath=title, rootBeanClass=class org.thoughts.on.java.model.Book, messageTemplate='{javax.validation.constraints.NotNull.message}’}]] 18:21:33,233 INFO TestAttributeValidation:50 – ConstraintViolationImpl{interpolatedMessage=’may not be null’, propertyPath=title, rootBeanClass=class org.thoughts.on.java.model.Book, messageTemplate='{javax.validation.constraints.NotNull.message}’}
The same happens, when I change the title attribute to a value that is shorter than 5 or longer than 20 characters.
EntityManager em = emf.createEntityManager(); em.getTransaction().begin(); Book b = em.find(Book.class, 1000L); b.setTitle(“This is a very long title with more than 20 characters.”); try { em.getTransaction().commit(); Assert.fail(“ConstraintViolationException exptected”); } catch (RollbackException e) { log.error(e); } em.close();
18:59:40,241 ERROR ExceptionMapperStandardImpl:39 – HHH000346: Error during managed flush [Validation failed for classes [org.thoughts.on.java.model.Book] during update time for groups [javax.validation.groups.Default, ] List of constraint violations:[ConstraintViolationImpl{interpolatedMessage=’size must be between 5 and 20′, propertyPath=title, rootBeanClass=class org.thoughts.on.java.model.Book, messageTemplate='{javax.validation.constraints.Size.message}’}]]
Summary
BeanValidation provides a set of easy to use standard validations which you can use with Hibernate and all other JPA 2.x implementations. The only things you have to do are to add the required dependencies to your application’s classpath and apply the validation annotations to your entities. Hibernate will automatically trigger the validation on pre-persist and pre-update events so that you only store valid information in your database.
Hello @Thorben Janssen,
This is all good and easy, but let’s say the approach is not code-first, but instead database-first and then generate the entities with hibernate tools with hbm2java. Then how can you use Hibernate Validator on the generated entities? It’s not suitable to manually annotate every entity upon change of a table. Is there an existing possible solution?
I would greatly appreciate your opinion and help!
Thanks for your taken time! 🙂