What is Custom Validation in Spring Boot?
Custom Validation in Spring Boot is the process of creating user-defined validation rules when built-in validation annotations are not sufficient for business requirements.
Spring Boot already provides standard validation annotations such as:
@NotNull@Email@Size@Pattern
However, real-world enterprise applications often require advanced business-specific validation logic.
In such cases, developers create custom validation annotations and custom validator classes.
Why Custom Validation is Needed
Standard validations cannot handle every business rule.
Examples of real-world custom validation:
- Password strength validation
- Age eligibility validation
- Company email validation
- Custom account number format
- Employee ID validation
- Unique username validation
- GST number validation
- PAN card validation
These validations require custom business logic.
Example of Standard Validation Limitation
Suppose a company allows only official emails:
example@dhanishempower.com
Standard @Email validation only checks email format.
It cannot verify:
- Specific company domain
- Business-specific email rules
This is where custom validation becomes important.
How Custom Validation Works in Spring Boot
Custom validation mainly involves:
- Creating custom annotation
- Creating validator class
- Implementing validation logic
- Applying annotation on DTO fields
Validation Dependency
Add validation dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
Step-by-Step Example of Custom Validation
Use Case
Validate whether email belongs to:
@dhanishempower.com
Step 1: Create Custom Annotation
import jakarta.validation.Constraint;
import jakarta.validation.Payload;
import java.lang.annotation.*;
@Documented
@Constraint(validatedBy = CompanyEmailValidator.class)
@Target({ ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface CompanyEmail {
String message()
default "Invalid company email";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
Understanding Annotation Components
| Component | Purpose |
|---|---|
| @Constraint | Links validator class |
| validatedBy | Specifies validator implementation |
| message | Validation error message |
| groups | Validation groups support |
| payload | Additional metadata support |
Step 2: Create Validator Class
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
public class CompanyEmailValidator
implements ConstraintValidator<CompanyEmail, String> {
@Override
public boolean isValid(
String value,
ConstraintValidatorContext context) {
if(value == null) {
return false;
}
return value.endsWith("@dhanishempower.com");
}
}
Understanding ConstraintValidator
ConstraintValidator contains:
ConstraintValidator<AnnotationType, DataType>
Example:
CompanyEmail→ custom annotationString→ field type
Step 3: Use Custom Validation in DTO
public class EmployeeRequest {
@CompanyEmail
private String email;
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
Step 4: Use @Valid in Controller
@RestController
@RequestMapping("/employees")
public class EmployeeController {
@PostMapping
public String createEmployee(
@Valid @RequestBody EmployeeRequest request) {
return "Employee Created Successfully";
}
}
Valid Request
{
"email": "naresh@dhanishempower.com"
}
Output
Employee Created Successfully
Invalid Request
{
"email": "naresh@gmail.com"
}
Validation Error
{
"status": 400,
"errors": [
"Invalid company email"
]
}
Real-Time Custom Validation Examples
| Validation | Business Use Case |
|---|---|
| Password Strength | Strong password enforcement |
| Age Validation | Minimum age requirement |
| Company Email | Official employee email validation |
| GST Validation | Tax number verification |
| PAN Validation | Indian PAN card verification |
| Mobile Number Validation | Country-specific phone format |
Password Strength Custom Validation Example
Password Rules
- Minimum 8 characters
- At least one uppercase letter
- At least one lowercase letter
- At least one number
- At least one special character
Validator Logic
return value.matches(
"^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)"
+ "(?=.*[@#$%^&+=]).{8,}$"
);
Custom Validation with Database Check
Custom validation can also check database values.
Example:
- Username uniqueness
- Email already exists
- Duplicate product codes
Example: Unique Username Validation
@Component
public class UsernameValidator
implements ConstraintValidator<UniqueUsername, String> {
@Autowired
private UserRepository userRepository;
@Override
public boolean isValid(
String username,
ConstraintValidatorContext context) {
return !userRepository.existsByUsername(username);
}
}
Custom Validation with Multiple Fields
Some business rules require comparing multiple fields.
Example:
- Password and confirm password match
- Start date before end date
- Loan amount based on salary
Class-Level Validation Example
@PasswordMatches
public class RegisterRequest {
private String password;
private String confirmPassword;
}
Difference Between Standard and Custom Validation
| Feature | Standard Validation | Custom Validation |
|---|---|---|
| Flexibility | Limited | High |
| Business Logic Support | Basic | Advanced |
| Custom Rules | No | Yes |
| Database Integration | No | Yes |
Advantages of Custom Validation
- Supports business-specific rules
- Improves application security
- Enhances data integrity
- Provides reusable validation logic
- Improves user experience
- Supports enterprise applications
Disadvantages of Custom Validation
- Requires additional coding
- Complex validations may affect performance
- Improper logic may create validation issues
Best Practices for Custom Validation
- Keep validation logic reusable
- Use meaningful error messages
- Avoid heavy database queries inside validators
- Separate business validation properly
- Use DTO classes instead of entities
- Handle validation errors globally
Common Exceptions in Validation
| Exception | Description |
|---|---|
| MethodArgumentNotValidException | Request body validation failure |
| ConstraintViolationException | Validation constraint violation |
Global Exception Handling for Validation
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(
MethodArgumentNotValidException.class
)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public List<String> handleValidationException(
MethodArgumentNotValidException ex) {
List<String> errors = new ArrayList<>();
ex.getBindingResult()
.getFieldErrors()
.forEach(error ->
errors.add(error.getDefaultMessage()));
return errors;
}
}
Common Interview Questions on Custom Validation
What is custom validation in Spring Boot?
Custom validation is creating user-defined validation logic for business-specific requirements.
Why is custom validation needed?
Standard validation annotations cannot handle all business rules.
What interface is used for custom validation?
ConstraintValidator interface is used.
What is the purpose of @Constraint?
@Constraint links custom annotation with validator class.
Can custom validation access database?
Yes. Custom validators can use repositories and services.
Conclusion
Custom validation is an important feature in Spring Boot for implementing advanced business-specific validation logic.
It allows developers to create reusable, flexible, and enterprise-grade validation mechanisms beyond standard annotations.
Custom validation improves data integrity, application security, business rule enforcement, and user experience.
Understanding custom validation is essential for Spring Boot developers because enterprise applications frequently require advanced validation rules that standard annotations cannot provide.