Spring Boot Validation: Understanding @Valid vs @Validated with End-to-End Examples
One of the most confusing topics for Spring Boot developers is understanding the difference between @Valid and @Validated. Many developers wonder: Should I use @Valid or @Validated? Canβ¦
One of the most confusing topics for Spring Boot developers is understanding the difference between @Valid and @Validated. Many developers wonder:
- Should I use
@Validor@Validated? - Can I use both together?
- Why does
@RequestBodyvalidation work without@Validated? - Why doesn’t
@PathVariablevalidation work with only@Valid?
In this article, we’ll answer all these questions and build a clear understanding of field-level validation in a Spring Boot microservice.
What is Bean Validation?
Bean Validation is a specification (Jakarta Bean Validation) that allows us to validate Java objects using annotations such as:
@NotBlank@NotNull@Email@Size@Pattern@Positive@Min@Max
Instead of manually writing validation logic, we simply annotate our DTO fields.
Example:
public class CustomerRequest {
@NotBlank(message = "Customer name is mandatory")
private String name;
@Email(message = "Invalid email")
private String email;
@Pattern(
regexp = "^[6-9]\\d{9}$",
message = "Invalid mobile number"
)
private String mobile;
}
Now the framework validates these fields automatically.
Why Should We Validate DTOs Instead of Entities?
A common mistake beginners make is placing validation annotations inside JPA entities.
For example:
@Entity
public class Customer {
@NotBlank
private String name;
}
Although this works, it is not recommended.
Instead, validate your request DTO.
public class CustomerRequest {
@NotBlank
private String name;
}
Why?
Entities represent database tables.
DTOs represent API requests.
Keeping validation inside DTOs ensures:
- Clean separation of concerns
- Reusable entities
- Different validation rules for Create and Update operations
Understanding @Valid
Suppose we have the following controller.
@RestController
@RequestMapping("/customers")
public class CustomerController {
@PostMapping
public ResponseEntity<String> saveCustomer(
@Valid @RequestBody CustomerRequest request) {
return ResponseEntity.ok("Customer Saved");
}
}
Notice the annotation:
@Valid
@RequestBody CustomerRequest request
This tells Spring:
Before executing the controller method, validate every field inside
CustomerRequest.
If the request is valid, execution continues.
If validation fails, Spring throws:
MethodArgumentNotValidException
Example Request
{
"name": "",
"email": "abc",
"mobile": "11111"
}
Since all three fields are invalid, Spring never enters the controller.
Instead, it throws an exception.
How Validation Actually Works
Many developers think @Valid itself performs validation.
That’s not entirely true.
The actual flow looks like this:
HTTP Request
β
βΌ
@RequestBody
β
βΌ
Spring creates CustomerRequest object
β
βΌ
@Valid detected
β
βΌ
Jakarta Bean Validation executes
β
βΌ
Validation Passed?
β
ββββββ΄βββββ
β β
Yes No
β β
βΌ βΌ
Controller Method
β
βΌ
MethodArgumentNotValidException
Notice something interesting.
We never used @Validated.
Yet validation worked perfectly.
Why?
Because Spring automatically validates objects annotated with @RequestBody when @Valid is present.
So What is @Validated?
@Validated is a Spring Framework annotation.
Unlike @Valid, it enables method-level validation.
This includes:
@PathVariable@RequestParam- Method parameters
- Validation Groups
Example Without @Validated
@RestController
@RequestMapping("/customers")
public class CustomerController {
@GetMapping("/{id}")
public String getCustomer(
@Positive
@PathVariable Long id){
return "Success";
}
}
Now call
GET /customers/-10
Surprisingly…
No validation happens.
Why?
Because Long id is just a method parameter.
Spring doesn’t automatically validate method parameters.
Adding @Validated
Now modify the controller.
@RestController
@RequestMapping("/customers")
@Validated
public class CustomerController {
@GetMapping("/{id}")
public String getCustomer(
@Positive(message = "Id must be positive")
@PathVariable Long id){
return "Success";
}
}
Now call
GET /customers/-10
Spring throws
ConstraintViolationException
Validation finally works.
Why Does This Happen?
The flow becomes
HTTP Request
β
βΌ
@PathVariable
β
βΌ
Method Validation Proxy (@Validated)
β
βΌ
Bean Validation
β
βΌ
Controller Method
Without @Validated, this proxy never gets created.
Request Parameter Validation
Consider the following API.
@GetMapping
public String search(
@Size(min = 3)
@RequestParam String name){
return "Success";
}
Calling
GET /customers?name=ab
Again…
Nothing happens.
Now enable
@RestController
@Validated
public class CustomerController {
The same request now throws
ConstraintViolationException
Can We Use Both Together?
Yes.
In fact, this is the most common approach used in enterprise Spring Boot applications.
@RestController
@RequestMapping("/customers")
@Validated
public class CustomerController {
@PostMapping
public ResponseEntity<CustomerResponse> create(
@Valid @RequestBody CustomerRequest request){
return ResponseEntity.ok(service.save(request));
}
@GetMapping("/{id}")
public ResponseEntity<CustomerResponse> getCustomer(
@Positive
@PathVariable Long id){
return ResponseEntity.ok(service.find(id));
}
}
Here:
@Validatedenables method-level validation.@Validvalidates the request body.
They complement each other rather than replace each other.
Exceptions Thrown
Different validations produce different exceptions.
DTO Validation
@Valid
@RequestBody CustomerRequest request
throws
MethodArgumentNotValidException
Path Variable Validation
@Positive
@PathVariable Long id
throws
ConstraintViolationException
Request Parameter Validation
@RequestParam
@Size(min = 3)
String name
also throws
ConstraintViolationException
Global Exception Handling
A production application usually handles both exceptions.
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<?> handleRequestBodyValidation(
MethodArgumentNotValidException ex){
// Handle DTO validation errors
}
@ExceptionHandler(ConstraintViolationException.class)
public ResponseEntity<?> handleMethodValidation(
ConstraintViolationException ex){
// Handle PathVariable and RequestParam validation errors
}
}
This ensures every validation failure returns a consistent error response.
@Valid vs @Validated
| Feature | @Valid | @Validated |
|---|---|---|
Validates @RequestBody | β | β |
Validates @PathVariable | β | β |
Validates @RequestParam | β | β |
| Method-level validation | β | β |
| Validation Groups | β | β |
| Package | Jakarta Validation | Spring Framework |
Which One Should You Use?
For real-world Spring Boot microservices, the recommended pattern is simple:
@RestController
@RequestMapping("/customers")
@Validated
public class CustomerController {
@PostMapping
public ResponseEntity<CustomerResponse> create(
@Valid @RequestBody CustomerRequest request){
return ResponseEntity.ok(service.save(request));
}
}
Even if your controller currently only validates request bodies, adding @Validated prepares the controller for future method parameter validation.
Best Practices
- Validate only request DTOs, not JPA entities.
- Always use
@Validwith@RequestBody. - Add
@Validatedat the controller level for method parameter validation. - Handle both
MethodArgumentNotValidExceptionandConstraintViolationExceptionin a global exception handler. - Return a consistent error response across all microservices.
- Keep bean validation (format, required fields, length) in the DTO layer.
- Keep business validation (email already exists, duplicate customer, invalid business rules) in the service layer.
Final Thoughts
Understanding the distinction between @Valid and @Validated is essential for building robust Spring Boot applications.
Think of them this way:
@Validvalidates the contents of an object (typically a request body).@Validatedenables validation of method parameters and supports advanced features like validation groups.
In enterprise applications, you’ll often see them used together because they solve different problems. Knowing when and why to use each annotation will help you write cleaner, more maintainable, and production-ready REST APIs.