如何通过反射或任何其他方式手动触发Javax验证?

时间:2018-10-23 16:03:40

标签: java spring validation bean-validation hibernate-validator

我正在使用validation-api-2.0.1.Finalhibernate-validator-6.0.13.Final。我想对以下情况进行验证,

我已经创建了一个自定义验证来验证List<Map<String,Object>>

BookInfo.java

@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(
        validatedBy = {BookInfoValidator.class}
)
public @interface BookInfo {
    String message() default "Should not be empty";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}

BookInfoValidator.java

public class BookInfoValidator implements ConstraintValidator<ValidateUserInfo, List<Map<String, Object>>> {

    private final ContentRepositoryClient contentRepository;

    public ValidateUserInfoValidator(ContentRepositoryClient contentRepository) {
        this.contentRepository = contentRepository;
    }

    @Override
    public void initialize(ValidateUserInfo constraintAnnotation) {

    }

    @Override
    public boolean isValid(List<Map<String,Object>> map, ConstraintValidatorContext constraintValidatorContext) {
        //In the list of Map the key will be "text,email,date etc etc" based on the key i would like to
        //validate with the proper validation constraints
        //ex) for Email invoke javax.validation.constraints.Email.class from validation-api
        //I am not sure how to manually invoke the validation annotations.
        return false;
    }
}

BookInfoView.java

class BookInfoView {
        @BookInfo
        private List<Map<String, Object>> bookInfos;
    }

在“地图”列表中,键为“文本,电子邮件,日期等”。基于密钥,我想使用适当的验证约束进行验证 电子邮件从验证API调用javax.validation.constraints.Email.class的异常。我不确定如何手动调用验证批注。

任何提示或帮助将不胜感激。

2 个答案:

答案 0 :(得分:4)

  

我不确定如何手动调用验证注释。

我正在回答以上引用的行。 ,可以以编程方式调用验证,如果验证失败,您将收到一组中的所有失败消息。以下是执行相同操作的步骤:

  1. 构建ValidatorFactory
  2. Validator获取ValidatorFactory实例
  3. 使用validate()方法进行验证
  4. 处理验证结果constraintViolations.iterator().next().getMessage()

显示一些代码,下面是上述所有四个步骤的代码段:

ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
Set<ConstraintViolation<BookInfoView>> constraintViolations = validator.validate(bookInfoViewObj);
assertEquals( "Should not be empty", constraintViolations.iterator().next().getMessage() );

Hibernate Validator框架提供了各种其他功能来验证一个或多个实体,然后处理结果。最好您看看official document

答案 1 :(得分:0)

访问约束的验证器实现没有“不错”的方式(电子邮件,非null等)。虽然您可以创建这些验证器的实例并将其存储在BookInfoValidator中,但是您需要做很多其他工作。对于每个验证器,其ConstraintValidator#initialize()方法。尽管在诸如@NotNull这样的简单约束的情况下,实际上要注意进行初始化,但是如果没有该验证器,则可以轻松地执行相同的检查。而且,对于像@Email这样的更复杂的类,您需要为注释创建自己的代理类,以便正确初始化约束验证器。

话虽如此,我建议为您的Map写一个包装类,例如:

public class BookInfoWrapper {
    private final Map<String, Object> data;

    public BookInfoWrapper(Map<String, Object> data) {
        this.data = data;
    }

    @NotNull
    public Map<String, Object> getUser(){
        return (Map<String, Object>) data.get( "user" );
    }

    @Email
    public String getEmail(){
        return Objects.toString(( getUser() ).get( "email" ));
    }

    // and any other constraints you need
}

然后在验证之前将地图列表转换为这些包装器。

我还可以看到您的验证器中有一个存储库,因此我认为您可能希望“动态”导出规则。在这种情况下,您可能想查看Hibernate Validator提供的programmatic API。使用它,您应该能够根据从数据库中检索到的数据来构建所需的规则。但是,仍然需要先包装地图。

总结一下,遗憾的是,还没有针对您的特定情况的简便解决方案。我们正在对自由格式对象进行验证,但是要花一些时间才能发布它。因此,我建议您要么

  • BookInfoValidator中自己编写验证检查,而无需使用内置约束。
  • 使用上述包装方法。