Spring Boot: From Basics to Production · Validation and Error Handling
Custom Constraints and Cross-Field Validation
Write reusable validation annotations and class-level checks.
When built-in constraints aren't enough, create a custom constraint: an annotation plus a ConstraintValidator. Class-level constraints handle cross-field rules (end date after start date, matching passwords). Keep validators fast and side-effect free; validators are Spring beans, so they can receive dependencies, but avoid heavy I/O.
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = DateRangeValidator.class)
public @interface ValidDateRange {
String message() default "endDate must be after startDate";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
public class DateRangeValidator implements ConstraintValidator<ValidDateRange, BookingRequest> {
@Override
public boolean isValid(BookingRequest value, ConstraintValidatorContext ctx) {
if (value == null || value.startDate() == null || value.endDate() == null) return true; // let @NotNull handle nulls
return value.endDate().isAfter(value.startDate());
}
}
@ValidDateRange
public record BookingRequest(@NotNull LocalDate startDate, @NotNull LocalDate endDate, @Min(1) int guests) {}
Common pitfalls
- Validators that return false for null (duplicating @NotNull and producing double errors).
- Database calls in validators for every request.
- Generic messages that don't tell users which field is wrong.
Key points
- Annotation + ConstraintValidator
- Class-level for cross-field rules
- Treat null as valid; combine with @NotNull
Further reading: Jakarta Bean Validation spec
Practice questions
Why should custom validators usually treat null as valid?
Answer
So null checks stay the job of @NotNull; otherwise you get duplicate error messages and can't make a field optional.
How do you validate that two fields relate correctly?
Answer
Use a class-level constraint whose validator receives the whole object and compares the fields.
Open in the app to mark lessons complete, take notes and track your progress.