Reputation: 3091
Situation: you have module with DTO objects used in your API, so that other project(s) can reuse then when sending requests. These DTO classes does have bean-validation annotations in them. And you would like to use your custom validations to validate DTO "arriving" via requests. The sender typically does not validate outgoing data, IIUC, and might not be interested in importing validators along with annotations.
Problem(?): bean-validation is defined in a way, where annotation defines who implements it (which is incorrect and it should be otherwise around imo), with possibility to specify empty array as annotation validator (seems like hack) and then pairing is done via manual hashmap manipulations instead of stuff like service loader etc.
How do you do this?
{}
as validator and then use org.hibernate.validator.internal.metadata.core.ConstraintHelper#putValidatorDescriptors
to bind them together, but I did not test it yet + maybe there is better way...Upvotes: 4
Views: 980
Reputation: 3091
I we need to separate interface class and validator implementation into separate modules, it's possible. And even in a way, which I said in original question, that should be used. In API module you declare validation for example as:
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = {})
@SupportedValidationTarget(ValidationTarget.ANNOTATED_ELEMENT)
@ReportAsSingleViolation
public @interface AnyUuid {
//...
notice validatedBy = {}
. The validator implementation looks like:
public class AnyUuidValidator implements ConstraintValidator<AnyUuid, Object> {
//...
and pairing can be setup using service loader(see javadoc if you don't know how that works). Put into file META-INF/services/javax.validation.ConstraintValidator
FQDN of AnyUuidValidator
shown above. And all other custom validators. And that should be it.
There is a bug I found with this. If I'm not mistaken. If you have DTO you cannot change (~annotate with constraints) and still want to validate them via bean validation, you can register validation definitions via xml file. If you are doing so and use service loader for pairing definition and implementation of custom validators, there is probably some bug and your custom validators won't be found. So verify this scenario before relying on service loader. But maybe I'm wrong, for me it was feasible to drop this validation trivially so I did to save some time and could ignore this.
Upvotes: 0
Reputation: 11
I agree that the annotation defining the validator does feel backwards. While not ideal, I've been able to work around this by separating my custom ConstraintValidator into an interface and implementation.
Example:
In api module define constraint and interface validator
@Constraint(validatedBy = MyConstraintValidator.class)
public @interface MyConstraint
{
}
public interface MyConstraintValidator
extends ConstraintValidator<MyConstraint, String>
{
}
In your service module define the implementation
public class MyConstraintValidatorImpl implements MyConstraintValidator
{
private FooService foo;
@Override
public boolean isValid( String value, ConstraintValidatorContext ctx)
{
// Implement your constraint logic
}
}
Upvotes: 1