I can't find it explicitly stated in any of the documentation for JSR303/JSR380 bean validation (Jakarta Validation), but do all fields to which you apply validations have to be "essentially" plain-old-data (POD) types, like Strings and ints and Longs and such?
I tried to apply a regular expression validator to a UUID field, and I got a NoProviderFoundException
thrown. I worked around it by just changing that field to a String
and putting the onus of converting the field into a UUID
on the consumer(s) of that class, but is there any way to create a custom "bean validation provider" mapped to an arbitrary non-POD class for cases where implementing a workaround isn't as straightforward?
Note: java.util.UUID is a serializable class, and therefore perfectly valid to include in a Bean.
Bean validation works for types, as long as the constraint annotation has a matching ConstraintValidator defined for it. I don't think that you can add support for extra types for the out-of-the-box annotations, but if you create your own custom annotation you can support all types you want.
A quick-and-dirty example based on @Pattern
:
@Target({ElementType.FIELD, ElementType.METHOD}) // add others as needed
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = UuidValidator.class) // one for each type you want to support
@Documented
public @interface UuidPattern {
String regexp();
// mandated properties
String message() default "UUID doesn't match pattern {regexp}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
public class UuidValidator implements ConstraintValidator<UuidPattern, UUID> {
private Pattern pattern;
@Override
public void initialize(UuidPattern annotation) {
pattern = Pattern.compile(annotation.regexp());
}
@Override
public boolean isValid(UUID uuid, ConstraintValidatorContext constraintValidatorContext) {
if (uuid == null) {
// let @NotNull handle this case
return true;
}
return pattern.matcher().matches(uuid.toString());
}
}
}