Reputation: 43
I have a project which publishes a service contract, eg endpoints and model classes. I have created a custom Jakarta validation which checks that when a date range is provided, the end date must be later or equal to the start date. Eg:
@Constraint(validatedBy = DateRangeValidator.class)
public @interface DateRangeValid {
...
}
public class DateRangeValidator implements ConstraintValidator<DateRangeValid, Object> {
...
}
However, this seems like it creates a very tight coupling between the annotation and valid, since both reference each other.
Is there a way to decouple these 2? By, say, having only the Validator reference the annotation, and not the other way round?
When I look at the validations that come as part of Jakarta, eg @Max, I see the annotation does not reference any validator:
@Constraint(
validatedBy = {}
)
public @interface Max {
...
}
But when I try the same on my custom annotation, I get the following error in my tests:
jakarta.validation.UnexpectedTypeException: HV000030: No validator could be found for constraint
Does anyone know an approach to solve this? Ideally I'd like to only publish the Annotation in my service contract, and keep the validation logic internal to my service so that it is easier to change in future if required.
Upvotes: 0
Views: 278
Reputation: 9175
There needs to be a mapping from constraint annotation to the validators that are used to enforce the constraint. For out-of-the-box annotations these validators are mapped by the framework implementation (usually Hibernate Validator). For custom annotations that's usually done through the validatedBy
annotation attribute. The only other way is to add this mapping programmatically. I don't think that can be done with ConstraintValidatorFactory
as suggested by Sharad Paul because that already needs the validator class.
I've found that Hibernate's ConstraintDefinitionContext interface has a method to add a validator to a constraint, but I couldn't find a way to use it without overwriting all of the annotation-based constraint mappings.
I've also found ServiceLoaderBasedConstraintMappingContributor that, according to How to register custom ConstraintMapping for validations defined in validation-constraints.xml, should allow you to provide your validators through the ServiceLoader
mechanism. Perhaps this is the most flexible you're going to get.
Upvotes: 0