0 day streak
java / intermediate
Snippet

Enforcing Custom Domain Data Constraints with ConstraintValidator

Custom validation annotations in Spring leverage Jakarta Bean Validation alongside Spring's dependency injection. By annotating the ConstraintValidator implementation with @Component or letting Spring discover it, the validator can inject other beans and perform domain-specific input assertions directly on incoming request payloads and records.

snippet.java
java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = IbanChecksumValidator.class)
@Documented
public @interface ValidIban {
String message() default "Invalid IBAN checksum structure";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
@Component
public class IbanChecksumValidator implements ConstraintValidator<ValidIban, String> {
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if (value == null || value.isBlank()) {
return true;
}
String sanitized = value.replaceAll("\\s+", "");
return sanitized.matches("^[A-Z]{2}\\d{2}[A-Z0-9]{1,30}$");
}
}
public record TransferRequest(@ValidIban String destinationIban, BigDecimal amount) {}
spring
Breakdown
1
@Constraint(validatedBy = IbanChecksumValidator.class)
Binds the validation annotation to its concrete validation logic implementation class.
2
public class IbanChecksumValidator implements ConstraintValidator<ValidIban, String>
Implements validation checks for String fields annotated with the custom @ValidIban annotation.
3
public record TransferRequest(@ValidIban String destinationIban, BigDecimal amount) {}
Applies domain validation directly to record components, evaluated during @Valid controller binding.