Custom Validation Annotations in Spring Boot (Complete In-Depth Guide)
Spring Boot provides many built-in validation annotations like @NotNull,
@Email, and @Size.
But in real applications, these are often not enough.
This is where custom validation annotations become extremely important.
- Why and when custom validation is needed
- How custom validation works internally
- Step-by-step creation of a custom annotation
- Advanced examples used in real projects
- Common mistakes and interview tips
1️⃣ Why Do We Need Custom Validation?
Built-in annotations cover only generic cases. Real-world APIs require business-specific validation.
Examples:
- Email must belong to company domain
- Password must contain uppercase, lowercase, number
- User age must match role rules
- Mobile number format depends on country
2️⃣ How Custom Validation Works Internally
Spring Boot custom validation is based on Bean Validation. Each custom annotation is connected to a Validator class.
@CustomAnnotation
↓
ConstraintValidator
↓
isValid() method
↓
true → validation passed
false → validation failed
This mechanism integrates seamlessly with @Valid in REST APIs.
If you’re new to validation basics, read: Spring Boot REST API Validation (All Annotations)
3️⃣ Step-by-Step: Creating a Custom Validation Annotation
Step 1: Create the Custom Annotation
@Target({ ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = CompanyEmailValidator.class)
public @interface CompanyEmail {
String message() default "Email must belong to company domain";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
Important parts:
- @Constraint links annotation to validator
- message is default error message
- groups & payload are required by Bean Validation spec
Step 2: Create the Validator Class
public class CompanyEmailValidator
implements ConstraintValidator<CompanyEmail, String> {
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if (value == null) return true; // let @NotNull handle null
return value.endsWith("@company.com");
}
}
Step 3: Use Custom Annotation in DTO
public class UserRequest {
@NotBlank
private String name;
@CompanyEmail
private String email;
}
This works exactly like built-in annotations.
4️⃣ Using Custom Validation in REST Controller
@PostMapping("/users")
public String createUser(
@Valid @RequestBody UserRequest request) {
return "User created";
}
If validation fails, Spring throws an exception automatically.
Related: Spring Boot Annotations Explained
5️⃣ Advanced Example: Password Strength Validation
Custom Annotation
@Constraint(validatedBy = PasswordStrengthValidator.class)
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface StrongPassword {
String message() default "Password is too weak";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
Validator Implementation
public class PasswordStrengthValidator
implements ConstraintValidator<StrongPassword, String> {
@Override
public boolean isValid(String password, ConstraintValidatorContext context) {
if (password == null) return false;
boolean hasUpper = password.matches(".*[A-Z].*");
boolean hasLower = password.matches(".*[a-z].*");
boolean hasDigit = password.matches(".*\\d.*");
return password.length() >= 8 && hasUpper && hasLower && hasDigit;
}
}
6️⃣ Class-Level Custom Validation (Cross-Field)
Sometimes validation depends on multiple fields. Example: password and confirmPassword must match.
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = PasswordMatchValidator.class)
public @interface PasswordMatch {
String message() default "Passwords do not match";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
Validator
public class PasswordMatchValidator
implements ConstraintValidator<PasswordMatch, UserRequest> {
@Override
public boolean isValid(UserRequest user, ConstraintValidatorContext context) {
return user.getPassword().equals(user.getConfirmPassword());
}
}
7️⃣ Handling Custom Validation Errors
Custom validation errors are handled the same way as built-in ones.
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public Map<String, String> handleValidationErrors(
MethodArgumentNotValidException ex) {
Map<String, String> errors = new HashMap<>();
ex.getBindingResult().getFieldErrors()
.forEach(error ->
errors.put(error.getField(), error.getDefaultMessage())
);
return errors;
}
}
Deep dive: Global Exception Handling in Spring Boot
8️⃣ Common Mistakes Freshers Make
- Putting business logic in controller instead of validator
- Returning false for null instead of combining @NotNull
- Using Entity instead of DTO for validation
- Not writing reusable validators
9️⃣ Interview Questions on Custom Validation
- Why create custom validation annotations?
- Difference between field-level and class-level validation?
- What is ConstraintValidator?
- How is custom validation triggered?
Final Summary
- Custom validation handles business rules cleanly
- Validators keep controllers thin
- Reusable, testable, and interview-friendly
If you can confidently explain custom validation annotations, you already stand out as a strong Spring Boot developer.
✅ Build Cleaner & Safer Spring Boot APIs
Custom validation annotations help eliminate repetitive logic and improve API reliability. Strengthen your Spring Boot skills by exploring these closely related REST and validation topics.
๐งพ Spring Boot REST API Validation Annotations
Learn built-in validation annotations and how they work alongside custom validators.
๐จ Spring Boot Global Exception Handling
Handle validation errors consistently
using @ControllerAdvice.
๐ท️ Spring Boot Annotations for REST APIs
Understand commonly used Spring annotations for building clean REST APIs.
๐ฏ Controller vs RestController
Learn when to use @Controller
and @RestController correctly.
๐ Spring Boot Interview Questions (Freshers)
Prepare for entry-level interviews with commonly asked Spring Boot questions.
๐ผ Spring Boot Interview Questions (2–5 Years)
Interview questions covering validation, REST APIs, and real-world Spring Boot practices.