Week 4 Day 5 — Spring MVC Validation Deep Dive
Goal
Today I want to understand validation deeply in Spring MVC REST APIs.
Main questions:
- What is Bean Validation?
- Why do REST APIs need validation?
- Which dependency do I need?
- What is the difference between
@Validand@Validated? - What are common validation annotations?
- What is the difference between
@NotNull,@NotEmpty, and@NotBlank? - How do I validate request bodies?
- How do I validate nested DTOs?
- How do I validate lists?
- How do I validate query parameters?
- How do I validate path variables?
- How do I create a custom validator?
- What exceptions happen when validation fails?
- What are common exam traps?
1. Quick Review from Week 4 Day 4
In Day 4, I learned:
@ExceptionHandlerhandles exceptions.@ControllerAdviceapplies across controllers.@RestControllerAdviceequals@ControllerAdviceplus@ResponseBody.MethodArgumentNotValidExceptioncommonly represents failed@Valid @RequestBody.- Invalid JSON usually returns
400 Bad Request. - Missing resources usually return
404 Not Found. - Business conflicts often return
409 Conflict. - Error responses should be safe and structured.
Memory sentence:
Exception -> Handler -> Error DTO -> JSON response.
Today I go deeper into validation.
2. What Is Validation?
Validation means checking whether input data is acceptable before the application uses it.
Example rules:
name must not be blank
email must be valid
age must be at least 18
page must not be negative
size must be between 1 and 100
password must have enough characters
startDate must be before endDate
items list must not be empty
Simple definition:
Validation checks whether client input follows the rules.
Memory sentence:
Validation protects the application from bad input.
3. Why REST APIs Need Validation
Without validation, bad data can enter the system.
Possible problems:
empty names
invalid emails
negative prices
too-large page sizes
missing required fields
invalid date ranges
business rules violated
database errors later
unclear error responses
security risks
Example bad request:
{
"title": "",
"priority": "",
"dueDate": "not-a-date"
}
A good API should reject this early with:
400 Bad Request
and a clear error response.
4. Bean Validation
Bean Validation is the standard Java validation model.
It uses annotations like:
@NotBlank
@Email
@Size
@Min
@Max
@Positive
Example:
public record CreateUserRequest(
@NotBlank
String name,
@Email
String email
) {
}
These annotations declare validation rules.
Memory sentence:
Bean Validation means validation rules written as annotations on Java objects.
5. Dependency Needed
In Spring Boot, add:
implementation("org.springframework.boot:spring-boot-starter-validation")
Maven:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
Without this dependency, validation annotations may not be available or validation may not run correctly.
Memory sentence:
For Bean Validation in Spring Boot, add
spring-boot-starter-validation.
6. Important Imports
Modern Spring Boot uses Jakarta Validation packages.
Common imports:
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Positive;
Older projects may use:
javax.validation.*
For modern Spring Boot 3+:
use jakarta.validation.*
Memory sentence:
Spring Boot 3+ uses
jakarta.validation, notjavax.validation.
7. Request Body Validation
Request DTO:
public record CreateTaskRequest(
@NotBlank
@Size(max = 100)
String title,
@NotBlank
String priority
) {
}
Controller:
@PostMapping("/api/tasks")
public TaskDto create(
@Valid @RequestBody CreateTaskRequest request
) {
return taskService.create(request);
}
Important:
@Valid triggers validation.
@RequestBody reads JSON body.
Without @Valid, the annotations may not be checked.
Memory sentence:
Validation annotations define rules.
@Validtriggers checking.
8. What Happens When Request Body Validation Fails?
Request:
POST /api/tasks
Content-Type: application/json
{
"title": "",
"priority": ""
}
DTO:
public record CreateTaskRequest(
@NotBlank String title,
@NotBlank String priority
) {
}
Controller:
public TaskDto create(@Valid @RequestBody CreateTaskRequest request) {
return taskService.create(request);
}
Result:
Controller method body does not run.
Spring returns 400 Bad Request.
Common exception:
MethodArgumentNotValidException
This exception contains field errors.
9. Common Validation Annotations
| Annotation | Meaning |
|---|---|
@NotNull | value must not be null |
@NotEmpty | string, collection, map, or array must not be null or empty |
@NotBlank | string must not be null, empty, or whitespace |
@Size(min, max) | size/length must be within range |
@Min(value) | number must be at least value |
@Max(value) | number must be at most value |
@Positive | number must be greater than zero |
@PositiveOrZero | number must be zero or greater |
@Negative | number must be less than zero |
@Email | string must be email-like |
@Pattern | string must match regex |
@Past | date must be in the past |
@PastOrPresent | date must be past or present |
@Future | date must be in the future |
@FutureOrPresent | date must be future or present |
@AssertTrue | boolean must be true |
@AssertFalse | boolean must be false |
10. @NotNull vs @NotEmpty vs @NotBlank
This is very important.
@NotNull
Value cannot be null.
@NotNull
String name;
Invalid:
null
Still valid:
""
" "
@NotEmpty
Value cannot be null or empty.
@NotEmpty
String name;
Invalid:
null
""
Still valid:
" "
Also works for collections:
@NotEmpty
List<String> items;
@NotBlank
For strings.
Value cannot be null, empty, or only whitespace.
@NotBlank
String name;
Invalid:
null
""
" "
Memory sentence:
For required text fields, usually use
@NotBlank.
11. @Size
@Size checks length or collection size.
String:
@Size(min = 3, max = 50)
String username;
Collection:
@Size(min = 1, max = 10)
List<String> tags;
Important:
@Size does not mean value cannot be null.
This can pass:
null
If you need required and size:
@NotBlank
@Size(min = 3, max = 50)
String username;
Memory sentence:
@Sizechecks size, not null by itself.
12. Number Validation
Example:
public record PageRequest(
@Min(0)
int page,
@Min(1)
@Max(100)
int size
) {
}
Meaning:
page must be 0 or more
size must be between 1 and 100
For prices or amounts:
@Positive
BigDecimal price;
For optional positive value:
@Positive
Integer quantity;
Important:
If Integer is null, @Positive does not fail.
Add @NotNull if it is required.
Example:
@NotNull
@Positive
Integer quantity;
13. Date Validation
Example:
public record CreateTaskRequest(
@FutureOrPresent
LocalDate dueDate
) {
}
Meaning:
dueDate must be today or in the future
For birth date:
@Past
LocalDate birthDate;
Important:
If the date field is required, add @NotNull.
Example:
@NotNull
@FutureOrPresent
LocalDate dueDate;
14. Email Validation
public record RegisterUserRequest(
@NotBlank
@Email
String email
) {
}
Why both?
@NotBlank checks required text.
@Email checks email format.
Memory sentence:
Combine annotations when you need multiple rules.
15. Regex Validation with @Pattern
Example:
public record CreateClientRequest(
@Pattern(regexp = "^[A-Z]{2}[0-9]{6}$")
String clientCode
) {
}
This might accept values like:
DE123456
But reject:
de123456
ABC123
For readability, use clear messages:
@Pattern(
regexp = "^[A-Z]{2}[0-9]{6}$",
message = "clientCode must look like DE123456"
)
String clientCode;
16. Custom Validation Messages
Default messages can be generic.
Example:
@NotBlank(message = "Title is required")
@Size(max = 100, message = "Title must not exceed 100 characters")
String title;
Response field errors can show:
{
"field": "title",
"message": "Title is required"
}
Memory sentence:
Custom messages make validation errors more user-friendly.
17. Nested DTO Validation
Request:
{
"name": "Client A",
"address": {
"street": "",
"city": ""
}
}
DTO:
public record CreateClientRequest(
@NotBlank
String name,
@Valid
@NotNull
AddressRequest address
) {
}
Nested DTO:
public record AddressRequest(
@NotBlank
String street,
@NotBlank
String city
) {
}
Important:
@Valid on address triggers nested validation.
@NotNull makes address required.
Without @Valid, nested fields may not be checked.
Memory sentence:
For nested DTOs, put
@Validon the nested field.
18. Nested DTO Trap
Bad:
public record CreateClientRequest(
@NotBlank
String name,
AddressRequest address
) {
}
Nested DTO:
public record AddressRequest(
@NotBlank String street,
@NotBlank String city
) {
}
Problem:
street and city may not be validated because address is not annotated with @Valid.
Better:
public record CreateClientRequest(
@NotBlank
String name,
@Valid
@NotNull
AddressRequest address
) {
}
19. List Validation
Request:
{
"items": [
{
"productId": 1,
"quantity": 2
}
]
}
DTO:
public record CreateOrderRequest(
@NotEmpty
List<@Valid OrderItemRequest> items
) {
}
Nested item:
public record OrderItemRequest(
@NotNull
Long productId,
@Positive
int quantity
) {
}
Meaning:
items must not be empty
each item must be validated
productId must not be null
quantity must be positive
Memory sentence:
For list elements, use
List<@Valid ItemDto>.
20. List Element Constraint
You can validate list elements directly.
Example:
public record TagRequest(
@NotEmpty
List<@NotBlank String> tags
) {
}
Meaning:
tags list cannot be empty
each tag cannot be blank
Invalid:
{
"tags": ["java", "", "spring"]
}
21. Map Validation
Example:
public record MetadataRequest(
Map<@NotBlank String, @NotBlank String> metadata
) {
}
Meaning:
map keys cannot be blank
map values cannot be blank
This is less common in simple REST APIs but useful to know.
22. @Valid vs @Validated
@Valid
From Jakarta Validation.
Common use:
public TaskDto create(@Valid @RequestBody CreateTaskRequest request) {
}
Use it for:
request body validation
nested object validation
simple Bean Validation
@Validated
Spring annotation.
Common use:
@RestController
@Validated
public class TaskController {
}
Useful for:
method parameter validation
validation groups
Spring-specific validation support
Exam-safe sentence:
@Validis standard Bean Validation.@Validatedis Spring’s variant and supports validation groups.
23. Request Body: @Valid or @Validated
Both can trigger validation on request body objects.
Example with @Valid:
@PostMapping("/api/tasks")
public TaskDto create(@Valid @RequestBody CreateTaskRequest request) {
return taskService.create(request);
}
Example with @Validated:
@PostMapping("/api/tasks")
public TaskDto create(@Validated @RequestBody CreateTaskRequest request) {
return taskService.create(request);
}
For most request DTOs:
@Valid is enough and common.
24. Query Parameter Validation
Example:
@RestController
@RequestMapping("/api/tasks")
public class TaskController {
@GetMapping
public List<TaskDto> list(
@RequestParam(defaultValue = "0") @Min(0) int page,
@RequestParam(defaultValue = "20") @Min(1) @Max(100) int size
) {
return taskService.findPage(page, size);
}
}
Request:
GET /api/tasks?page=-1&size=500
Invalid:
page must be at least 0
size must be at most 100
Modern Spring MVC has built-in method validation support for controller method parameters.
Memory sentence:
Put validation annotations directly on query parameters to validate them.
25. Query Parameter Validation with @Validated
In many Spring Boot applications, you may see:
@RestController
@Validated
@RequestMapping("/api/tasks")
public class TaskController {
@GetMapping
public List<TaskDto> list(
@RequestParam(defaultValue = "0") @Min(0) int page,
@RequestParam(defaultValue = "20") @Min(1) @Max(100) int size
) {
return taskService.findPage(page, size);
}
}
This style is common.
Important modern note:
Spring MVC also has built-in method validation support.
Depending on Spring version and configuration, parameter validation can raise HandlerMethodValidationException or another constraint-related exception.
Exam-safe memory:
Request body validation commonly raises
MethodArgumentNotValidException; method parameter validation can raiseHandlerMethodValidationExceptionin modern Spring MVC.
26. Path Variable Validation
Example:
@GetMapping("/api/tasks/{id}")
public TaskDto get(
@PathVariable @Positive Long id
) {
return taskService.findById(id);
}
Invalid request:
GET /api/tasks/-1
Expected:
400 Bad Request
because id must be positive.
27. Header Validation
Example:
@GetMapping("/api/tasks")
public List<TaskDto> list(
@RequestHeader("X-Tenant-Id") @NotBlank String tenantId
) {
return taskService.findForTenant(tenantId);
}
Invalid if:
X-Tenant-Id is blank
Usually, tenant and auth validation may also be handled in filters/security layers, but this shows the validation concept.
28. Request Parameter Object
Instead of many query params:
@GetMapping("/api/tasks")
public List<TaskDto> list(
@RequestParam(defaultValue = "0") @Min(0) int page,
@RequestParam(defaultValue = "20") @Min(1) @Max(100) int size,
@RequestParam(required = false) String status,
@RequestParam(required = false) String search
) {
}
You can use a filter object:
public class TaskSearchRequest {
@Min(0)
private int page = 0;
@Min(1)
@Max(100)
private int size = 20;
private String status;
private String search;
// getters and setters
}
Controller:
@GetMapping("/api/tasks")
public List<TaskDto> list(@Valid TaskSearchRequest request) {
return taskService.search(request);
}
For query parameter objects, Spring binds request parameters to the object.
Memory sentence:
For many query parameters, use a request/filter object.
29. @ModelAttribute Note
For non-body objects in Spring MVC, binding often works like @ModelAttribute.
This:
public List<TaskDto> list(@Valid TaskSearchRequest request)
is often treated similarly to:
public List<TaskDto> list(@Valid @ModelAttribute TaskSearchRequest request)
For REST APIs, you do not always write @ModelAttribute, but the concept is useful.
Memory sentence:
Query/form parameters can bind to an object, not only individual parameters.
30. Custom Cross-Field Validation
Sometimes one field is not enough.
Example rule:
startDate must be before endDate
DTO:
@ValidDateRange
public record CreateProjectRequest(
@NotNull
LocalDate startDate,
@NotNull
LocalDate endDate
) {
}
We need a custom annotation and validator.
31. Custom Validation Annotation
Create annotation:
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = DateRangeValidator.class)
public @interface ValidDateRange {
String message() default "startDate must be before or equal to endDate";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
Important parts:
@Constraint connects annotation to validator
message defines default error message
groups supports validation groups
payload is required by Bean Validation API
32. Custom Constraint Validator
public class DateRangeValidator
implements ConstraintValidator<ValidDateRange, CreateProjectRequest> {
@Override
public boolean isValid(CreateProjectRequest value, ConstraintValidatorContext context) {
if (value == null) {
return true;
}
if (value.startDate() == null || value.endDate() == null) {
return true;
}
return !value.startDate().isAfter(value.endDate());
}
}
Why return true when fields are null?
@NotNull should handle missing dates.
This validator only checks the relationship between dates.
Memory sentence:
Single-field rules use built-in annotations. Cross-field rules often need custom validators.
33. Custom Field-Level Validator
Example rule:
priority must be LOW, MEDIUM, or HIGH
Better option:
public enum Priority {
LOW, MEDIUM, HIGH
}
DTO:
public record CreateTaskRequest(
@NotNull Priority priority
) {
}
But if the value must be String, create custom annotation:
@Target({ ElementType.FIELD, ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = TaskPriorityValidator.class)
public @interface ValidTaskPriority {
String message() default "priority must be LOW, MEDIUM, or HIGH";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
Validator:
public class TaskPriorityValidator
implements ConstraintValidator<ValidTaskPriority, String> {
private static final Set<String> ALLOWED =
Set.of("LOW", "MEDIUM", "HIGH");
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if (value == null) {
return true;
}
return ALLOWED.contains(value);
}
}
DTO:
public record CreateTaskRequest(
@NotBlank
String title,
@NotBlank
@ValidTaskPriority
String priority
) {
}
34. Prefer Enum When Possible
Instead of this:
@NotBlank
@ValidTaskPriority
String priority;
Often better:
@NotNull
Priority priority;
Why?
type safety
less custom code
clear allowed values
compiler support
cleaner service code
Memory sentence:
Prefer enum for fixed sets of values.
35. Validation Groups
Sometimes validation differs between create and update.
Example:
Create: title is required.
Update: title may be optional.
Define groups:
public interface CreateValidation {
}
public interface UpdateValidation {
}
DTO:
public record TaskRequest(
@NotBlank(groups = CreateValidation.class)
String title,
@Size(max = 100, groups = { CreateValidation.class, UpdateValidation.class })
String description
) {
}
Controller:
@PostMapping("/api/tasks")
public TaskDto create(
@Validated(CreateValidation.class)
@RequestBody TaskRequest request
) {
return taskService.create(request);
}
@PatchMapping("/api/tasks/{id}")
public TaskDto update(
@PathVariable Long id,
@Validated(UpdateValidation.class)
@RequestBody TaskRequest request
) {
return taskService.update(id, request);
}
Memory sentence:
Validation groups let different rules run in different situations.
36. Use Validation Groups Carefully
Validation groups can become complicated.
Often simpler:
CreateTaskRequest
UpdateTaskRequest
Example:
public record CreateTaskRequest(
@NotBlank String title,
@Size(max = 100) String description
) {
}
public record UpdateTaskRequest(
@Size(max = 100) String description
) {
}
This is often easier to read.
Memory sentence:
Separate DTOs are often simpler than validation groups.
37. Validation vs Business Rules
Validation should check basic input rules.
Examples:
not blank
valid email
size range
positive number
date format
required fields
Business rules belong in service layer.
Examples:
user cannot delete another tenant's task
invoice cannot be sent twice
task cannot be completed before all subtasks are done
subscription must be active
client must belong to current firm
Memory sentence:
Validation checks input shape. Services check business rules.
38. Example: Validation + Business Rule
DTO validation:
public record CompleteTaskRequest(
@NotNull
Long taskId
) {
}
Service business rule:
public TaskDto completeTask(Long taskId, Long currentUserId) {
Task task = taskRepository.findById(taskId)
.orElseThrow(() -> new ResourceNotFoundException("Task", taskId));
if (!task.canBeCompletedBy(currentUserId)) {
throw new ForbiddenOperationException("User cannot complete this task");
}
task.complete();
return toDto(task);
}
Validation checks:
taskId is present
Service checks:
whether current user may complete the task
39. Validation Error Response
From Day 4:
public record ValidationErrorResponse(
Instant timestamp,
int status,
String error,
String code,
String message,
String path,
List<FieldErrorDto> fieldErrors
) {
}
public record FieldErrorDto(
String field,
String message
) {
}
Example:
{
"timestamp": "2026-07-07T18:30:00Z",
"status": 400,
"error": "Bad Request",
"code": "VALIDATION_ERROR",
"message": "Request validation failed",
"path": "/api/tasks",
"fieldErrors": [
{
"field": "title",
"message": "Title is required"
}
]
}
40. Handling MethodArgumentNotValidException
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ValidationErrorResponse> handleValidationError(
MethodArgumentNotValidException ex,
HttpServletRequest request
) {
List<FieldErrorDto> fieldErrors = ex.getBindingResult()
.getFieldErrors()
.stream()
.map(error -> new FieldErrorDto(
error.getField(),
error.getDefaultMessage()
))
.toList();
ValidationErrorResponse response = new ValidationErrorResponse(
Instant.now(),
HttpStatus.BAD_REQUEST.value(),
HttpStatus.BAD_REQUEST.getReasonPhrase(),
"VALIDATION_ERROR",
"Request validation failed",
request.getRequestURI(),
fieldErrors
);
return ResponseEntity.badRequest().body(response);
}
Use this for failed @Valid @RequestBody.
41. Handling Method Validation Errors
Modern Spring MVC can raise:
HandlerMethodValidationException
for method parameter validation.
Example invalid:
GET /api/tasks?page=-1
Controller:
@GetMapping("/api/tasks")
public List<TaskDto> list(
@RequestParam @Min(0) int page
) {
return taskService.findPage(page);
}
Exam-safe handler idea:
@ExceptionHandler(HandlerMethodValidationException.class)
public ResponseEntity<ApiErrorResponse> handleMethodValidation(
HandlerMethodValidationException ex,
HttpServletRequest request
) {
ApiErrorResponse error = new ApiErrorResponse(
Instant.now(),
HttpStatus.BAD_REQUEST.value(),
HttpStatus.BAD_REQUEST.getReasonPhrase(),
"METHOD_VALIDATION_ERROR",
"Request parameter validation failed",
request.getRequestURI()
);
return ResponseEntity.badRequest().body(error);
}
For the certificate, know:
Request body validation and method parameter validation may produce different exception types.
42. BindingResult Alternative
You may see this style:
@PostMapping("/api/tasks")
public ResponseEntity<?> create(
@Valid @RequestBody CreateTaskRequest request,
BindingResult bindingResult
) {
if (bindingResult.hasErrors()) {
return ResponseEntity.badRequest().body("Validation failed");
}
return ResponseEntity.ok(taskService.create(request));
}
This handles validation locally inside the controller method.
But in REST APIs, often better:
Let validation throw exception.
Handle globally in @RestControllerAdvice.
Memory sentence:
BindingResultis local handling.@ControllerAdviceis global handling.
43. Good Validation Design for REST APIs
Recommended style:
Use request DTOs.
Put validation annotations on DTO fields.
Use @Valid on @RequestBody.
Use @Valid for nested DTOs.
Use query parameter constraints for pagination.
Use global exception handling.
Return structured validation errors.
Keep business rules in services.
44. Common Validation Mistakes
Mistake 1
Validation annotations exist, but @Valid is missing.
public TaskDto create(@RequestBody CreateTaskRequest request)
Fix:
public TaskDto create(@Valid @RequestBody CreateTaskRequest request)
Mistake 2
Nested object has validation annotations, but parent field misses @Valid.
AddressRequest address
Fix:
@Valid
AddressRequest address
Mistake 3
Using @NotNull for required text.
@NotNull
String title
This allows:
""
" "
Better:
@NotBlank
String title
Mistake 4
Using @Size alone for required field.
@Size(min = 3)
String title
This may allow:
null
Better:
@NotBlank
@Size(min = 3)
String title
Mistake 5
Putting business rules only in DTO validation.
Bad:
@ValidTenantAccess
on request DTO, when this depends on database/current user/security context.
Better:
service layer checks tenant access
45. Real Example for Klarsync-Like App
Request:
{
"title": "Prepare payroll documents",
"clientId": 10,
"dueDate": "2026-08-01",
"priority": "HIGH",
"assigneeEmail": "user@example.com"
}
DTO:
public record CreateWorkTaskRequest(
@NotBlank(message = "Title is required")
@Size(max = 120, message = "Title must not exceed 120 characters")
String title,
@NotNull(message = "Client id is required")
@Positive(message = "Client id must be positive")
Long clientId,
@NotNull(message = "Due date is required")
@FutureOrPresent(message = "Due date must not be in the past")
LocalDate dueDate,
@NotNull(message = "Priority is required")
Priority priority,
@Email(message = "Assignee email must be valid")
String assigneeEmail
) {
}
Controller:
@PostMapping("/api/work-tasks")
public ResponseEntity<WorkTaskDto> create(
@Valid @RequestBody CreateWorkTaskRequest request
) {
WorkTaskDto created = workTaskService.create(request);
URI location = URI.create("/api/work-tasks/" + created.id());
return ResponseEntity.created(location).body(created);
}
46. Validation Flow
1. Client sends JSON.
2. @RequestBody tells Spring to read body.
3. Jackson converts JSON to DTO.
4. @Valid triggers Bean Validation.
5. If valid, controller method runs.
6. If invalid, Spring raises validation exception.
7. @RestControllerAdvice handles exception.
8. Client receives 400 with field errors.
Memory sentence:
JSON -> DTO -> validation -> controller or 400 error.
47. Common Exam Traps
Trap 1
Validation annotations alone are not enough for request bodies.
Need:
@Valid @RequestBody
Trap 2
@NotNull does not reject empty strings.
Use @NotBlank for required text.
Trap 3
@Size does not imply @NotNull.
Use both if needed.
Trap 4
Nested DTO validation needs @Valid on the nested field.
Trap 5
List element validation needs List<@Valid ItemDto> or List<@NotBlank String>.
Trap 6
For fixed allowed values, enum is often better than custom string validation.
Trap 7
Request body validation and query parameter validation may throw different exception types.
Trap 8
Validation checks input shape.
Business rules belong in service/domain logic.
Trap 9
@Validated supports validation groups.
Trap 10
Use global exception handling for consistent validation error responses.
48. Real Exam Question: Bean Validation
Question:
What is Bean Validation?
Answer:
Bean Validation is the standard Java validation model that uses annotations such as @NotBlank, @Email, @Size, @Min, and @Max to declare validation rules on Java objects.
49. Real Exam Question: Dependency
Question:
Which Spring Boot starter is commonly needed for validation?
Answer:
implementation("org.springframework.boot:spring-boot-starter-validation")
50. Real Exam Question: @Valid
Question:
What does @Valid do with @RequestBody?
Answer:
@Valid triggers Bean Validation for the object created from the request body.
51. Real Exam Question: @Validated
Question:
What is @Validated?
Answer:
@Validated is Spring’s validation annotation. It can trigger validation and supports validation groups. It is often used for method parameter validation or group-based validation.
52. Real Exam Question: @NotNull vs @NotBlank
Question:
What is the difference between @NotNull and @NotBlank?
Answer:
@NotNull only rejects null. @NotBlank rejects null, empty strings, and strings containing only whitespace.
53. Real Exam Question: Nested Validation
Question:
How do I validate a nested DTO?
Answer:
Put validation annotations on the nested DTO fields and put @Valid on the nested field in the parent DTO.
54. Real Exam Question: List Validation
Question:
How do I validate each object in a list?
Answer:
Use:
List<@Valid ItemRequest> items
and usually add @NotEmpty to ensure the list is not empty.
55. Real Exam Question: Query Parameter Validation
Question:
How do I validate query parameters?
Answer:
Put constraint annotations directly on the method parameters, such as:
@RequestParam @Min(0) int page
Depending on Spring version/configuration, method parameter validation may require @Validated or use Spring MVC’s built-in method validation.
56. Real Exam Question: MethodArgumentNotValidException
Question:
When does MethodArgumentNotValidException commonly happen?
Answer:
It commonly happens when validation fails for an object such as @Valid @RequestBody.
57. Real Exam Question: HandlerMethodValidationException
Question:
When can HandlerMethodValidationException happen?
Answer:
In modern Spring MVC, it can happen when method validation is applied to controller method parameters, such as constraints directly on @RequestParam, @PathVariable, or return values.
58. Real Exam Question: Validation vs Business Rules
Question:
What is the difference between validation and business rules?
Answer:
Validation checks basic input shape and constraints, such as required fields, size, email format, or positive numbers. Business rules check application-specific logic, such as whether a user may access a tenant or whether an invoice can be sent twice.
59. Interview Answer
Question:
How do you validate a request body in Spring Boot?
Good answer:
I create a request DTO and add Bean Validation annotations such as @NotBlank, @Size, or @Email. I add spring-boot-starter-validation, then annotate the controller parameter with @Valid @RequestBody. If validation fails, Spring usually returns 400 Bad Request, and I handle MethodArgumentNotValidException in a global @RestControllerAdvice to return a structured error response.
60. Interview Answer
Question:
What is the difference between
@Validand@Validated?
Good answer:
@Valid is the standard Jakarta Bean Validation annotation and is commonly used for request body and nested object validation. @Validated is Spring’s variant. It can also trigger validation and supports validation groups. It is often used for method parameter validation or group-based validation.
61. Interview Answer
Question:
How do you validate nested DTOs?
Good answer:
I put validation annotations on the nested DTO fields, and I put @Valid on the nested field in the parent DTO. If the nested object is required, I also add @NotNull. Without @Valid on the nested field, the nested object’s validation rules may not run.
62. Interview Answer
Question:
How do you validate query parameters?
Good answer:
I put constraint annotations directly on the controller method parameters, for example @RequestParam @Min(0) int page and @RequestParam @Max(100) int size. In many Spring Boot applications, @Validated is used on the controller class for method parameter validation. In modern Spring MVC, method validation can also be handled by built-in support and may raise HandlerMethodValidationException.
63. Interview Answer
Question:
When would you create a custom validator?
Good answer:
I create a custom validator when built-in annotations are not enough. For example, if I need to validate that startDate is before endDate, I create a custom constraint annotation and a ConstraintValidator. For fixed values like priority, I prefer using an enum when possible because it is simpler and type-safe.
64. Tiny Code Practice
Create DTO:
public record CreateClientRequest(
@NotBlank
@Size(max = 100)
String name,
@Email
String email,
@Valid
@NotNull
AddressRequest address
) {
}
public record AddressRequest(
@NotBlank
String street,
@NotBlank
String city
) {
}
Controller:
@PostMapping("/api/clients")
public ResponseEntity<ClientDto> create(
@Valid @RequestBody CreateClientRequest request
) {
ClientDto created = clientService.create(request);
URI location = URI.create("/api/clients/" + created.id());
return ResponseEntity.created(location).body(created);
}
Questions:
- What validates
name? - What validates
email? - What triggers validation for the request body?
- What triggers nested address validation?
- What status should invalid input usually return?
Answers:
@NotBlankand@Size@Email@Validon the controller parameter@Validon theaddressfield400 Bad Request
65. Tiny Bug Practice 1
Problem:
public record CreateClientRequest(
@NotBlank
String name,
AddressRequest address
) {
}
public record AddressRequest(
@NotBlank String street,
@NotBlank String city
) {
}
Nested address fields are not validated.
Question:
What is missing?
Answer:
@Valid is missing on the nested field.
Fix:
public record CreateClientRequest(
@NotBlank
String name,
@Valid
AddressRequest address
) {
}
66. Tiny Bug Practice 2
Problem:
public record CreateTaskRequest(
@Size(min = 3)
String title
) {
}
Request:
{
"title": null
}
Validation passes unexpectedly.
Question:
Why?
Answer:
@Size checks length if a value exists, but it does not reject null. Add @NotBlank or @NotNull.
Fix:
public record CreateTaskRequest(
@NotBlank
@Size(min = 3)
String title
) {
}
67. Tiny Bug Practice 3
Problem:
public record CreateTaskRequest(
@NotNull
String title
) {
}
Request:
{
"title": " "
}
Validation passes.
Question:
Why?
Answer:
@NotNull only checks that the value is not null. It does not reject empty or whitespace strings. Use @NotBlank.
Practice Questions and Answers
Question 1
What is validation?
Answer:
Validation means checking whether client input follows the required rules before the application uses it.
Question 2
What is Bean Validation?
Answer:
Bean Validation is the standard Java validation model that uses annotations on Java objects, such as @NotBlank, @Email, @Size, and @Min.
Question 3
Which dependency do I need for validation in Spring Boot?
Answer:
Use:
implementation("org.springframework.boot:spring-boot-starter-validation")
Question 4
What does @Valid do?
Answer:
@Valid triggers Bean Validation for an object, such as a request DTO or nested DTO.
Question 5
What does @Validated do?
Answer:
@Validated is Spring’s validation annotation. It can trigger validation and supports validation groups.
Question 6
What is the difference between @NotNull, @NotEmpty, and @NotBlank?
Answer:
@NotNull rejects only null. @NotEmpty rejects null and empty values. @NotBlank rejects null, empty strings, and whitespace-only strings.
Question 7
Does @Size reject null?
Answer:
No. @Size does not reject null by itself.
Question 8
How do I validate a request body?
Answer:
Put validation annotations on the request DTO and use @Valid @RequestBody in the controller method.
Question 9
How do I validate a nested DTO?
Answer:
Put validation annotations on the nested DTO fields and put @Valid on the nested field in the parent DTO.
Question 10
How do I validate each object in a list?
Answer:
Use List<@Valid ItemRequest> for objects, or constraints like List<@NotBlank String> for simple values.
Question 11
How do I validate query parameters?
Answer:
Put constraint annotations directly on query parameter method parameters, such as @RequestParam @Min(0) int page.
Question 12
How do I validate path variables?
Answer:
Put constraint annotations directly on path variable parameters, such as @PathVariable @Positive Long id.
Question 13
When should I create a custom validator?
Answer:
Create a custom validator when built-in annotations are not enough, especially for cross-field validation like start date before end date.
Question 14
Why should I prefer enum for fixed values?
Answer:
Enums are type-safe, clear, and avoid custom string validation for fixed sets of values.
Question 15
What are validation groups?
Answer:
Validation groups allow different validation rules to run in different situations, such as create vs update.
Question 16
When are separate DTOs better than validation groups?
Answer:
Separate DTOs are often better when create and update requests have different shapes, because they are simpler and easier to understand.
Question 17
What is the difference between validation and business rules?
Answer:
Validation checks basic input shape and constraints. Business rules check application-specific logic and usually belong in the service or domain layer.
Question 18
What exception commonly happens for failed @Valid @RequestBody?
Answer:
MethodArgumentNotValidException.
Question 19
What exception can happen for modern method parameter validation?
Answer:
HandlerMethodValidationException.
Question 20
What is the recommended style for validation error responses?
Answer:
Return a structured 400 Bad Request response with a stable error code, message, path, and field-level validation errors.
Final Memory Sentences
- Validation protects the application from bad input.
- Bean Validation uses annotations on Java objects.
- Spring Boot validation needs
spring-boot-starter-validation. - Spring Boot 3+ uses
jakarta.validation. @Validtriggers validation.@Validatedis Spring’s variant and supports groups.@NotNullrejects null only.@NotEmptyrejects null and empty.@NotBlankrejects null, empty, and whitespace-only text.@Sizedoes not reject null by itself.- Use
@Valid @RequestBodyfor request body validation. - Use
@Validon nested DTO fields. - Use
List<@Valid ItemDto>for list element validation. - Use constraints on
@RequestParamand@PathVariablefor method parameter validation. - Request body validation commonly raises
MethodArgumentNotValidException. - Modern method validation can raise
HandlerMethodValidationException. - Prefer enums for fixed values.
- Use custom validators for rules built-in annotations cannot express.
- Validation checks input shape.
- Business rules belong in service/domain logic.