Hibernate Validator - Add a Dynamic ConstraintValidator

寵の児 提交于 2019-12-04 21:09:09

问题


After learning about Hibernate Custom Validators, it has given me an interest in one topic, could I possibly create one base annotation wherein I could set which Validator to use?

@Target({ ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = validator().class)
public @interface CustomAnnotation {
    public String message();
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
    Class<? extends ConstraintValidator<? extends CustomAnnotation, Serializable>> validator();
}

So that I could use @CustomAnnotation in this manner

@CustomAnnotation(validator = CustomConstraintValidator.class, message = "validationMessage")
private Object fieldName;

回答1:


I would not recommend it but you can do it roughly this way:

@Target({ ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = GenericValidatorBootstrapperValidator.class)
public @interface CustomAnnotation {
    public String message();
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
    Class<? extends ConstraintValidator<? extends CustomAnnotation, Serializable>> validator();
}

public class GenericValidatorBootstrapperValidator implements ConstraintValidator<CustomAnnotation, Object> {

    private final ConstraintValidator validator;

    @Override
    public void initialize(CustomAnnotation constraintAnnotation) {
        Class<? extends ConstraintValidator> validatorClass = constraintAnnotation.validator();
        validator = validatorClass.newInstance();
        validator.initialize( ... ); //TODO with what?
    }

    @Override
    public boolean isValid(Object value, ConstraintValidatorContext context) {
        return validator.isValid(value, context);
    }
}

But again, prefer specific annotations, they are more expressive.

Edit

After your comment, I think what you want is to be able to set different validators based on the return type of the property

@CustomAnnotation
List<String> foo;

@CustomAnnotation
Table bar;

If that's the case, add several validators implementations in the @Constraint annotation.

@Target({ ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {ListValidatorImpl.class, TableValidatorImpl.class, ...})
public @interface CustomAnnotation {
    public String message();
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

public class ListValidatorImpl implements ConstraintValidator<CustomAnnotation, List> {

    @Override
    public boolean isValid(List value, ConstraintValidatorContext context) {
    }
}

public class TableValidatorImpl implements ConstraintValidator<CustomAnnotation, Table> {

    @Override
    public boolean isValid(Table value, ConstraintValidatorContext context) {
    }
}

You can even link a contraint annotation with an implementation via the META/validation.xml file

<constraint-mappings
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://jboss.org/xml/ns/javax/validation/mapping validation-mapping-1.1.xsd"
    xmlns="http://jboss.org/xml/ns/javax/validation/mapping" version="1.1">

    <constraint-definition annotation="org.mycompany.CustomAnnotation">
        <validated-by include-existing-validators="true">
            <value>org.mycompany.EnumCustomValidatorImpl</value>
        </validated-by>
    </constraint-definition>
</constraint-mappings>

If you need something more flexible, I think my initial proposal would work. In the GenericValidatorBootstrapperValidator isValid method, you could call the right validator instance based on the object type of the value parameter (via instanceof for example).




回答2:


Hibernate Validator also offers now a annotation @ScriptAssert which makes the implementation of custom validations easier and helps to avoid plenty lines of code.

Example of use:

 @ScriptAssert(lang = "javascript", 
    script = "_this.capital.equals(_this.capital.toUpperCase)",
    message = "capital has not Capital letters")
public class BigLetters {

    private String capital;

    public String getCapital() {
        return capital;
    }

    public void setCapital(String capital) {
        this.capital = capital;
    }

}



回答3:


I don't think you can implement a dynamic validator resolver on top of Hibernate Validator support. It's much better to have a dedicated set of annotation-validator pairs so when you annotate a field with a specific Validation annotation, it's clear what Validator is to be used.



来源:https://stackoverflow.com/questions/28360017/hibernate-validator-add-a-dynamic-constraintvalidator

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!