Hibernate Validator (Bean Validation)
Learn how to validate entity fields with Hibernate Validator using annotations like @NotNull, @Size, and @Email before persisting data to the database.
Introduction
So far, nothing has stopped you from saving an Employee with a blank name or a negative salary — Hibernate will happily generate the INSERT and send it to the database. Hibernate Validator closes that gap by letting you declare validation rules directly on your entity fields, and checking them before the data ever reaches the database.
Hibernate Validator is the reference implementation of Bean Validation (JSR 380 / Jakarta Bean Validation), the same way Hibernate ORM is the reference implementation of JPA. It integrates with Hibernate ORM so that entities are validated automatically at the point they are persisted or updated.
- What Bean Validation is and how Hibernate Validator implements it
- Common validation annotations: @NotNull, @Size, @Email, and more
- How to annotate entity fields with validation constraints
- How to validate manually with a Validator
- How validation runs automatically on persist/update
What Is Bean Validation?
Bean Validation is a Java standard for expressing validation rules as annotations on fields, rather than scattering manual if-checks throughout your code. Hibernate Validator implements that standard, and Hibernate ORM automatically triggers it right before an entity is inserted or updated, via a mechanism called pre-persist/pre-update validation.
Adding Hibernate Validator
Hibernate Validator ships as a separate dependency from Hibernate ORM itself. Add it alongside an expression language implementation, which the validator needs to build readable error messages.
<dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> <version>8.0.1.Final</version></dependency><dependency> <groupId>org.glassfish</groupId> <artifactId>jakarta.el</artifactId> <version>4.0.2</version></dependency>Common Validation Annotations
| Annotation | Checks |
|---|---|
| @NotNull | The value must not be null |
| @NotBlank | A String must not be null and must contain at least one non-whitespace character |
| @NotEmpty | A String, collection, or array must not be null or empty |
| @Size(min, max) | A String's length or a collection's size falls within the given bounds |
| @Min / @Max | A numeric value is at least / at most the given value |
| A String is a syntactically valid email address | |
| @Positive / @PositiveOrZero | A numeric value is greater than (or at least) zero |
| @Past / @Future | A date is in the past / future |
Annotating an Entity
import javax.persistence.*;import javax.validation.constraints.*;
@Entity@Table(name = "employees")public class Employee {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id;
@NotBlank(message = "Name must not be blank") @Size(min = 2, max = 50, message = "Name must be between 2 and 50 characters") private String name;
@NotBlank(message = "Email is required") @Email(message = "Email must be a valid address") private String email;
@NotNull(message = "Salary is required") @Positive(message = "Salary must be greater than zero") private Double salary;
// Getters and setters}Validating Manually
You can validate an object explicitly, without persisting it, using a Validator obtained from a ValidatorFactory. This is useful when you want to check data — for example, from a web form — before you even build the entity for persistence.
import javax.validation.*;import java.util.Set;
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();Validator validator = factory.getValidator();
Employee emp = new Employee();emp.setName("A");emp.setEmail("not-an-email");emp.setSalary(-500.0);
Set<ConstraintViolation<Employee>> violations = validator.validate(emp);
for (ConstraintViolation<Employee> violation : violations) { System.out.println(violation.getPropertyPath() + ": " + violation.getMessage());}Click Run to see what this code prints.
Validation on Persist
When Hibernate Validator is on the classpath alongside Hibernate ORM, validation runs automatically right before an entity is inserted or updated — you do not have to call the Validator yourself. A failed check throws a ConstraintViolationException instead of sending an invalid INSERT to the database.
Session session = factory.openSession();Transaction tx = session.beginTransaction();
try { Employee emp = new Employee(); emp.setName(""); emp.setEmail("bad-email"); emp.setSalary(-100.0);
session.persist(emp); tx.commit();} catch (javax.validation.ConstraintViolationException e) { tx.rollback(); e.getConstraintViolations().forEach(v -> System.out.println(v.getPropertyPath() + ": " + v.getMessage()) );} finally { session.close();}Click Run to see what this code prints.
Because this check runs inside Hibernate before the SQL is generated, no invalid row ever reaches the database — the transaction is rolled back and you get a clear, per-field error list instead of a cryptic database constraint violation.
Common Mistakes
- Forgetting to add hibernate-validator to the classpath and assuming annotations like @NotBlank are being enforced when they are silently ignored.
- Relying only on automatic persist-time validation and giving users no earlier, form-level feedback.
- Mixing up @NotNull, @NotEmpty, and @NotBlank and picking the wrong one for a String field.
- Not catching ConstraintViolationException, letting it surface as an unhandled 500 error.
- Validating only at the entity level when some rules (e.g., cross-field checks) need a custom validator instead.
Best Practices
- Add meaningful message text to every constraint so failures are easy to act on.
- Validate as early as possible (e.g., at the web layer) rather than waiting for the persist-time check to catch it.
- Use @NotBlank for user-facing text fields, not @NotNull, since a blank string still passes @NotNull.
- Keep validation rules on the entity itself so they stay enforced no matter which code path writes to it.
- Write custom constraint annotations for domain-specific rules that the built-in annotations cannot express.
Frequently Asked Questions
No, they are separate projects that happen to share a name and integrate closely. Hibernate Validator implements Bean Validation; Hibernate ORM implements JPA persistence.
No. It works standalone with plain Hibernate, though Spring Boot auto-configures it out of the box when it is on the classpath.
Hibernate throws a ConstraintViolationException before generating any SQL, and the transaction should be rolled back in response.
Yes, any Java object with Bean Validation annotations can be validated manually with a Validator, entirely independent of Hibernate persistence.
Key Takeaways
- Hibernate Validator is the reference implementation of Bean Validation (JSR 380).
- Annotations like @NotNull, @NotBlank, @Size, and @Email declare validation rules directly on entity fields.
- Validation can run manually via a Validator, or automatically at persist/update time.
- A failed automatic check throws ConstraintViolationException before any SQL is sent to the database.
- Custom constraint annotations extend Bean Validation for domain-specific rules.
Summary
Hibernate Validator lets you declare data quality rules right where your entity fields are defined, and enforces them automatically before persistence. Combined with transactions from the previous lesson, it ensures both consistency and correctness for every write your application makes.