Hibernate Validator - 添加动态ConstraintValidator

时间:2015-02-06 06:43:33

标签: java hibernate validation annotations hibernate-mapping

在了解了Hibernate Custom Validators之后,它让我对一个主题感兴趣,我是否可以创建一个基本注释,其中我可以设置使用哪个Validator?

@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();
}

这样我才能以这种方式使用@CustomAnnotation

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

3 个答案:

答案 0 :(得分:7)

我不推荐它,但你可以大致这样做:

@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);
    }
}

但同样,更喜欢特定的注释,它们更具表现力。

修改

在您发表评论之后,我认为您想要的是能够根据属性的返回类型设置不同的验证器

@CustomAnnotation
List<String> foo;

@CustomAnnotation
Table bar;

如果是这种情况,请在@Constraint注释中添加几个验证器实现。

@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) {
    }
}

您甚至可以通过META/validation.xml文件

将约束注释与实现相关联
<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>

如果你需要更灵活的东西,我认为我的初步建议是有效的。在GenericValidatorBootstrapperValidator isValid方法中,您可以根据value参数的对象类型调用正确的验证程序实例(例如,通过instanceof)。

答案 1 :(得分:1)

Hibernate Validator现在还提供了一个注释@ScriptAssert,它使自定义验证的实现更容易,并有助于避免大量代码。

使用示例:

 @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;
    }

}

答案 2 :(得分:0)

我认为您不能在Hibernate Validator支持的基础上实现动态验证器解析器。拥有一组专用的注释 - 验证器对会好得多,因此当您使用特定的验证注释注释某个字段时,它会明确使用哪个验证器。