简体   繁体   中英

Creating a constraint validator for an external, 3rd party annotation

I have an annotation from a third-party library to which I'd like to add a custom validator implementation. Let's call it @Requirement , and define it as follows:

@Target({PACKAGE, TYPE, METHOD, FIELD})
@Retention(RUNTIME)
@interface Requirement {}

Now I would like to add a constraint validator without adding my own annotation into the mix. I cannot do this with the XML-based ( META-INF/validation.xml ) configuration, the service loader configuration (a javax.validation.ConstraintValidator file with my validator in it), nor can I with adding custom mappings to the HibernateValidatorConfiguration using LocalValidatorFactoryBean : all of these aforementioned possibilities end up checking for @Constraint sooner or later as well.

Is there any way whatsoever to add a @Constraint -less annotation with a validator implementation?

In my specific case, I am using Java 8 and Spring Boot 2.6.1 (which itself uses Hibernate Validator 6.2.0 and javax.validation:validation-api 2.0.1), but I am (of course) welcoming of information using any Java version and Spring version.

i think rewrite the validator implement may be achieve your goal. Below is the draft code:

@Log4j2
public class CustomHibernateValidator extends HibernateValidator {

    @Override
    public ValidatorFactory buildValidatorFactory(ConfigurationState configurationState) {
        ValidatorFactoryImpl validatorFactory = new ValidatorFactoryImpl(configurationState);
        CustomConstraintHelper customConstraintHelper = new CustomConstraintHelper();
        try {
            Field field = validatorFactory.getClass().getDeclaredField("constraintHelper");
            field.setAccessible(true);
            field.set(validatorFactory,customConstraintHelper);
        } catch (IllegalAccessException | NoSuchFieldException e) {
            log.error("{}",e);
        }
        customConstraintHelper.modify();

        return validatorFactory;
    }
}

class CustomConstraintHelper extends ConstraintHelper {

    public CustomConstraintHelper() {
        super();
    }

    void modify() {
        Field field = null;
        try {
            field = this.getClass().getSuperclass().getDeclaredField("builtinConstraints");
            field.setAccessible(true);

            Object o = field.get(this);
            
            Map<Class<? extends Annotation>, List<ConstraintValidatorDescriptor<?>>> tmpConstraints = new HashMap<>();
            tmpConstraints.putAll((Map<Class<? extends Annotation>, List<ConstraintValidatorDescriptor<?>>>) o);
            //inject your validator
            putConstraint(tmpConstraints, Requirement.class, RequirementValidator.class);
            field.set(this, tmpConstraints);
        } catch (NoSuchFieldException | IllegalAccessException e) {

        }

    }

    private static <A extends Annotation> void putConstraint(Map<Class<? extends Annotation>, List<ConstraintValidatorDescriptor<?>>> validators,
                                                             Class<A> constraintType, Class<? extends ConstraintValidator<A, ?>> validatorType) {
        validators.put(constraintType, Collections.singletonList(ConstraintValidatorDescriptor.forClass(validatorType, constraintType)));
    }

}

and use this implement to replace default hv via write xx.xx.CustomHibernateValidator to META-INF/services/javax.validation.spi.ValidationProvider

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM