JSR303验证 - 使用自定义类验证器中的组

时间:2011-03-03 15:09:12

标签: java validation recommendation-engine bean-validation

我们有一个用例,其中我们有一个构造相当差的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时,它会对这些组进行这些二次/三次调用。简单来说,目的是将自定义类验证器放在默认组中,因此验证此类的业务逻辑不会因为必须单独调用验证而将此丑陋的遗留设计的详细信息泄漏到其中。 / p>

思考?谢谢!

2 个答案:

答案 0 :(得分:0)

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

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

答案 1 :(得分:0)

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

约束界面:

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