Jakarta Validation
About
Bean Validation is a standard framework for declaring and enforcing validation rules on JavaBeans (POJOs) using annotations. It provides a way to validate the state of objects either automatically (e.g., during web requests in Spring) or manually (programmatically).
It originated as JSR-303, evolved to JSR-380 (Bean Validation 2.0), and now resides under the Jakarta EE umbrella as jakarta.validation.
This API does not implement validation logic itself. It defines metadata (annotations) and interfaces. The actual logic is implemented by a provider, most commonly Hibernate Validator.
Why is Jakarta Bean Validation important in Spring ?
It integrates seamlessly with Spring Web MVC and Spring Boot.
It supports both automatic validation of controller inputs and manual validation in service layers.
It enables declarative and reusable constraint definitions.
It standardizes validation across frameworks and layers.
Jakarta Bean Validation Components
1. Constraint Annotations
These are placed on class fields or method parameters:
@NotNull: Value must not be null.@NotEmpty: Value must not be null or empty (for strings, collections).
2. Meta Annotations
@Constraint: Used when defining custom constraints.@Valid: Triggers recursive validation on associated objects or collections.
3. Interfaces
jakarta.validation.Validator: The core interface to validate beans.jakarta.validation.ConstraintValidator<A extends Annotation, T>: Interface for implementing custom constraint logic.jakarta.validation.ConstraintViolation<T>: Represents a single validation error.
4. Bootstrap API
Validation.buildDefaultValidatorFactory()creates aValidatorFactorywhich provides aValidator.
How Spring Integrates with Jakarta Validation ?
When jakarta.validation (or javax.validation) API and a provider like Hibernate Validator is on the classpath, Spring Boot auto-configures:
LocalValidatorFactoryBean: A SpringValidatorthat delegates to Jakarta Validator.MethodValidationPostProcessor: Enables method-level validation using@Validated.
Dependencies
Spring Boot starter spring-boot-starter-web includes Hibernate Validator by default.
Spring Validation Flow
Spring integrates with the Jakarta Bean Validation API via the LocalValidatorFactoryBean and auto-wires it as a global validator.
There are two major validation triggers in Spring:
Method-level validation (Spring MVC controllers, service beans, etc.)
Manual (programmatic) validation using
Validator
Spring internally:
Detects the
@Validor@ValidatedannotationsDelegates to the
jakarta.validation.Validatorinterface (via Hibernate Validator)Collects
ConstraintViolations and throws exceptions like:MethodArgumentNotValidException(for body-bound beans)ConstraintViolationException(for method parameter validation)BindException(for form data)
1. Controller-level Validation on @RequestBody DTO
@RequestBody DTOInternal Workflow:
Deserialization: JSON request body is deserialized into
UserDtousing Jackson.Validation Trigger: Spring detects
@Validon the parameter.Validator Bean: Calls
validator.validate(userDto)usingLocalValidatorFactoryBean.Hibernate Validator executes all constraints like
@NotBlank,@Email.Failure: If constraints fail:
Spring throws
MethodArgumentNotValidException.Handled globally with
@ExceptionHandleror@ControllerAdvice.
Example:
Response:
2. Controller-level Validation on @RequestParam, @PathVariable
@RequestParam, @PathVariableInternal Workflow:
Uses method-level validation.
Triggers via Spring’s
MethodValidationPostProcessor.Detects
@Validatedon the class or method.Calls
executableValidator.validateParameters(...)If invalid: throws
ConstraintViolationException.
Important: @Validated must be applied at class level for method parameter validation:
3. Nested (Recursive) Validation with @Valid
@ValidInternal Workflow:
During traversal, Spring checks if a field has
@Valid.If yes, it descends into that object and applies all constraints.
Recursion happens automatically.
If one ItemDto has null name, it’s picked up as a nested constraint violation.
4. Service-layer (Method-level) Validation using @Validated
@ValidatedService-layer validation using @Validated allows us to validate method parameters or return values in any Spring-managed bean—especially in the service layer, where we might not rely on Spring MVC controller-level validation. It’s part of the Method Validation feature provided by Jakarta Bean Validation and integrated into Spring via proxies.
When we annotate a class with @Validated, Spring uses AOP (Aspect-Oriented Programming) to create a proxy that intercepts method calls and performs validation before the actual method runs. Internally, Spring uses the MethodValidationPostProcessor bean which wraps beans with a proxy capable of method validation.
Execution Flow:
Spring boot automatically registers a
MethodValidationPostProcessor.We annotate our class with
@Validated.Spring creates a proxy of the class.
Before executing our method, Spring uses the
ExecutableValidatorto:Validate method parameters
Optionally validate the return value
If validation fails, Spring throws a
ConstraintViolationException.
Example
Calling code:
Result:
Spring will throw a ConstraintViolationException because:
nameis blank (@NotBlank)ageis less than 18 (@Min(18))
5. Validation Groups Internally
How It Works:
Spring detects group classes passed in
@Validated(Update.class)Passes these group classes to the validator:
Only the constraints in that group are applie
6. Manual Validation using Validator
When and How Validation is Triggered ?
If I Add Jakarta Validation Annotations to a DTO and Populate It — Will Constraints Be Checked Automatically?
No, the constraints will not be checked automatically just because we annotated our DTO with validation annotations (like @NotBlank, @Email, etc.).
They are only enforced when explicitly triggered — either:
By Spring (e.g., using
@Valid,@Validated)Or manually by calling
Validator.validate(...)
Example
1. DTO With Constraints
2. Populating DTO Manually
What Happens Here?
Nothing is validated at this point.
Java doesn't throw errors just because annotations exist — they’re metadata.
The validation must be explicitly triggered.
if you have a custom class (e.g., an entity or DTO) annotated with Jakarta validation constraints, those constraints do nothing unless validation is explicitly triggered.
How to Trigger Validation ?
Option A: Manual Trigger
This will print:
Option B: Automatically via Spring
When used in a Spring controller or service, Spring triggers validation for us.
Controller:
Spring will call
validator.validate(userDto)If any violation, it throws
MethodArgumentNotValidException
Validation Groups
By default, all validations belong to the Default group. Groups allow conditional or staged validation.
Define Marker Interfaces
Apply to Fields
Validate with Groups
Spring uses @Validated (from org.springframework.validation.annotation) to support groups. @Valid does not support groups.
Custom Constraints
1. Define annotation
2. Implement logic
3. Use it in our bean
Last updated