Bean Validation (Jakarta Validation)
Bean Validation (Jakarta Validation)
Before a request ever reaches your business logic, you need confidence that the data it carries is structurally sound. Jakarta Bean Validation (formerly javax.validation, now jakarta.validation) is the standard Java specification that lets you express constraints directly on your model classes using annotations. Spring Boot 3 integrates it out of the box through Hibernate Validator, the reference implementation.
The Dependency You Need
Add the Spring Boot starter — it pulls in Hibernate Validator and the Jakarta Validation API automatically:
Without this starter the annotations compile fine but constraints are silently ignored at runtime — a common source of confusion for developers migrating from older Spring projects.
spring-boot-starter-web no longer bundles the validation starter since Spring Boot 2.3. Declare it explicitly in every module that validates input.
How Bean Validation Works
The specification defines a Validator that inspects an object's fields, properties, and constructor parameters against a set of declared constraints. Each constraint is an annotation backed by a ConstraintValidator implementation that contains the actual check logic. When Spring processes a @Valid or @Validated annotation on a method parameter, it invokes the validator before the method body executes. If any constraint fails, a MethodArgumentNotValidException is thrown.
jakarta.validation:jakarta.validation-api. Hibernate Validator is the implementation that provides the actual constraint validators, plus many extras beyond the spec. You code against the API; the implementation is swappable.
The Standard Constraint Annotations
The Jakarta Validation specification ships around 25 built-in constraints. The ones you will reach for most often are:
@NotNull— the field must not benull. Passes for empty strings and blank strings.@NotEmpty— must not benulland must have at least one character (or one element, for collections).@NotBlank— must not benull, not empty, and must contain at least one non-whitespace character. The right choice for user-supplied text fields.@Size(min, max)— constrains the length (String, array, Collection, Map) or count betweenminandmax. Both bounds are inclusive.@Min(value)/@Max(value)— numeric minimum and maximum (works onint,long,BigDecimal, etc.).@Email— the string must match a valid email address format according to the RFC standard.@Pattern(regexp)— the string must match the given regular expression.@Positive/@PositiveOrZero/@Negative— sign constraints for numeric types.@Past/@Future— temporal constraints forLocalDate,Instant, and related types.@Digits(integer, fraction)— limits the number of integer and fractional digits.
Annotating a DTO
The idiomatic pattern in Spring Boot is to annotate a plain Java class (usually called a request DTO or command object) that represents incoming data. Here is a realistic user-registration request:
Notice several patterns here worth internalizing:
- Use
@NotBlankrather than@NotNullfor String fields where an empty or blank string should also be rejected. - Always supply a
messageattribute that speaks to the end-user or API consumer, not to the developer. - Stack multiple annotations on the same field — they all run, and all failures are reported in one pass.
- For primitive wrapper types (
Integer,Long) use@NotNullseparately from@Min/@Maxbecause those numeric constraints do not imply non-null.
@NotNull vs @NotEmpty vs @NotBlank
These three are the source of most beginner mistakes. A side-by-side comparison:
@NotNull: passes for"", passes for" ", fails only fornull.@NotEmpty: fails fornulland"", passes for" ".@NotBlank: fails fornull,"", and" "— the strictest of the three for strings.
@NotBlank on user-facing strings (name, username, title). Reserve @NotNull for non-string fields (numbers, booleans, nested objects) where you simply need to assert presence. @NotEmpty is useful for collections and arrays.
The @Email Constraint in Practice
The spec's @Email annotation validates the structural format of an email address. By default Hibernate Validator's check is fairly lenient — it accepts some technically valid but unusual formats. For stricter validation matching RFC 5322, pass the regexp attribute or use Hibernate's own @Email with regexp:
In most APIs the standard @Email is sufficient. Reserve the regexp override for domains where you control the address format tightly (e.g., corporate internal tools).
@Size on Collections and Arrays
@Size is not limited to strings. It applies to any type with a measurable size:
When the list is null, @Size passes (null is considered valid by most constraints unless combined with @NotNull). Stack them when both presence and size matter.
Customising Default Messages with a Message Interpolator
Every constraint has a default message template stored in ValidationMessages.properties on the classpath. You can override them globally by placing your own ValidationMessages.properties at src/main/resources/ValidationMessages.properties:
The {min} and {max} placeholders are resolved from the annotation's attributes automatically.
Summary
Jakarta Bean Validation gives you a declarative, annotation-driven way to express data constraints directly on your model classes. The core constraints — @NotNull, @NotBlank, @NotEmpty, @Size, @Email, @Min, @Max, and their companions — cover the vast majority of real-world validation needs. Stack them freely, supply meaningful message values, and place them on request DTOs rather than domain entities to keep your validation layer decoupled from your persistence model. The next lesson shows how Spring Boot activates all of this automatically when you add @Valid to a controller method parameter.