【问题标题】:JSR303 Validation - Using groups from a custom class validatorJSR303 验证 - 使用来自自定义类验证器的组
【发布时间】:2011-07-08 03:24:44
【问题描述】:

我们有一个用例,其中我们有一个结构相当糟糕的 bean,其中包含如下字段:

public class DataBean {
    private boolean flag1;
    private boolean flag2;

    private String phone1;
    private String address1;
    private String city1;
    private String state1;

    private String phone2;
    private String address2;
    private String city2;
    private String state2;
}

仅当标志 [1|2] 为真时,我们才需要验证电话/地址/城市/州 [1|2]。糟糕,糟糕的设计,理所当然。

我们当前的策略是在每个“真实”数据字段上使用@NotNull(或任何我们需要的验证),并使用组指示符,如下所示:

public class DataBean {
    private boolean flag1;
    private boolean flag2;

    @NotNull(groups = Info.First.class)
    private String phone1;
    @NotNull(groups = Info.First.class)
    private String address1;
    @NotNull(groups = Info.First.class)
    private String city1;
    @NotNull(groups = Info.First.class)
    private String state1;

    @NotNull(groups = Info.Second.class)
    private String phone2;
    @NotNull(groups = Info.Second.class)
    private String address2;
    @NotNull(groups = Info.Second.class)
    private String city2;
    @NotNull(groups = Info.Second.class)
    private String state2;
}

在我们验证此 bean 的业务逻辑中(其中包含将由“默认”验证组验证的各种其他字段),我们将获得“默认”组的违规行为,然后检查 flag1 是否为true,如果是,则对 Info.First.class 运行验证,检查 flag2 是否为 true,然后对 Info.Second.class 运行验证。

现在的问题是......有没有办法从自定义类验证器连接到这些组?我设想有一个类验证器,它采用 flag1/flag2 属性及其相应的自定义组,当调用 isValid 时,它会为这些组执行这些二级/三级调用。简单地说,目的是自定义类验证器将位于默认组中,因此验证此类的业务逻辑不会因为必须单独调用验证而将这种丑陋的遗留设计的细节泄漏到其中。

想法?谢谢!

【问题讨论】:

    标签: java validation recommendation-engine bean-validation


    【解决方案1】:

    我不完全确定我已经掌握了您要解决的问题。我的解释是试图避免显式地为每个验证组单独调用,而是根据标志调用两个非默认组?不能只定义一些组序列并使用这些而不是标志吗?组序列的使用方式与组相同。他们唯一的事情是,如果一个组失败,他们将停止验证组。

    如果您需要验证始终根据标志验证所有组,您的自定义类验证器可以在传递给其初始化方法的约束注释上调用groups()

    【讨论】:

    • 我没有研究组序列,我会检查一下。谢谢。
    【解决方案2】:

    制作一个类级别的验证器并在其中初始化验证器。然后,您可以通过在每个字段上添加约束例外,按类级别约束的主要有效方法内的组来验证对象。见下文:

    约束接口:

    @Documented
    @Constraint(validatedBy = {DataBeanValidator.class})
    @Target({METHOD, FIELD, ANNOTATION_TYPE, TYPE})
    @Retention(RUNTIME)
    public @interface DataBeanConstraint {
    
        String message() default "validation.dataBean";
    
        Class<?>[] groups() default {};
    
        Class<? extends Payload>[] payload() default {};
    }
    

    验证器:

    public class DataBeanValidator implements ConstraintValidator<DataBeanConstraint, DataBean> {
    
        private Validator validator;
    
        @Override
        public void initialize(DataBeanConstraint constraintAnnotation) {
            ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
            validator = factory.getValidator();
        }
    
        @Override
        public boolean isValid(BeanData beanData, ConstraintValidatorContext context) {
            if (beanData == null) {
                return true;
            }
            if (beanData.isFlag1) {
                Set<ConstraintViolation<DataBean>> constraintViolations = validator.validate(beanData, Info.First.class);
                if (constraintViolations != null) {
                    for (ConstraintViolation<BeanData> constraintViolation : constraintViolations) {
                        context.disableDefaultConstraintViolation();
                        context.buildConstraintViolationWithTemplate("required field").
                                addNode(constraintViolation.getPropertyPath().toString())
                                .addConstraintViolation();
                    }
                }
            }
    
        }
    }
    

    类级验证器:

    @DataBeanConstraint
    public class DataBean {
        private boolean flag1;
        private boolean flag2;
    
        @NotNull(groups = Info.First.class)
        private String phone1;
        @NotNull(groups = Info.First.class)
        private String address1;
        @NotNull(groups = Info.First.class)
        private String city1;
        @NotNull(groups = Info.First.class)
        private String state1;
    
        @NotNull(groups = Info.Second.class)
        private String phone2;
        @NotNull(groups = Info.Second.class)
        private String address2;
        @NotNull(groups = Info.Second.class)
        private String city2;
        @NotNull(groups = Info.Second.class)
        private String state2;
    }
    

    【讨论】:

      猜你喜欢
      • 2013-07-13
      • 2014-09-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-27
      • 2018-03-18
      相关资源
      最近更新 更多