Java Bean验证中混淆了多个约束注释

时间:2015-06-05 06:33:07

标签: java bean-validation hibernate-validator

我对在字段上有多个约束注释的情况感到困惑,如下所示:

    public class Student
{
    @NotNull
    @Size(min = 2, max = 14, message = "The name '${validatedValue}' must be between {min} and {max} characters long")
    private String name;

    public String getName()
    {
        return name;
    }

    public void setName(String name)
    {
        this.name = name;
    }
}

测试用例:

public class StudentTest
{
    private static Validator validator;

    @BeforeClass
    public static void setUp()
    {
        ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        validator = factory.getValidator();

        System.out.println(Locale.getDefault());
    }

    @Test
    public void nameTest()
    {
        Student student = new Student();
        student.setName(null);

        Set<ConstraintViolation<Student>> constraintViolations = validator.validateProperty(student, "name");

        System.out.println(constraintViolations.size());
        System.out.println(constraintViolations.iterator().next().getMessage());

    }

}

结果是:

1 
Can't be null

也就是说,当违反@NotNull约束时,它将不会继续。是的,这是正确的情况。当一次检查失败时,我们不希望它检查下一个约束。但是当我使用自定义约束时,情况就不同了。

我定义了两个自定义约束ACheck和BCheck。

@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = { ACheckValidator.class })
public @interface ACheck
{
    String message() default "A check error";

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

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

@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = { BCheckValidator.class })
public @interface BCheck
{
    String message() default "B check error";

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

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

public class ACheckValidator implements ConstraintValidator<ACheck, String>
{

    public void initialize(ACheck constraintAnnotation)
    {
    }

    public boolean isValid(String value, ConstraintValidatorContext context)
    {
        return false;
    }

}

public class BCheckValidator implements ConstraintValidator<BCheck, String>
{

    public void initialize(BCheck constraintAnnotation)
    {
    }

    public boolean isValid(String value, ConstraintValidatorContext context)
    {
        return false;
    }

}

没有关于自定义约束的具体信息,我更改了Student.java并使用了这样的自定义约束:

@ACheck
@BCheck
private String name;

再次测试,结果是:

2
B check error

也就是说,当@ACheck约束被违反时,它也会检查@BCheck,为什么会发生这种情况,我忽略了什么呢?

2 个答案:

答案 0 :(得分:3)

  

当违反@NotNull约束时,它将不会继续

这是不正确的。它将继续检查所有其他约束。只是Size验证器将空值视为可接受的值。原因通常是,你想要

  • 非空的最小尺寸值:然后应用两个约束
  • 或可以为空的值,如果值存在,则必须具有最小大小:然后您只应用大小。

答案 1 :(得分:3)

你误解了那些验证者 - they have no guarantee of order

  

默认情况下,无论其属于哪个组,都不会按特定顺序评估约束。

这意味着您的#include <iostream> #include <stdlib.h> #include <stdio.h> #include <string.h> using namespace std; #define SOME_SIZE 20 int main() { char *a, *b; a = b = (char *)malloc(SOME_SIZE * sizeof(char)); strcpy(a,"You Are Right"); cout << &(*a) << endl; cout << &(*b) << endl; return 0; } 您的ACheck可能会失败,或两者兼而有之;它尚未确定首先会发生哪种故障。

如果您希望能够使用两个不同的注释定义排序,则必须使用BCheck来指定。

或者,如果您想快速失败,那么configure the validator to do so

@GroupSequence

我个人不鼓励这种方法,因为它意味着验证失败的用户必须在每次出错时向资源发出重复请求,而不是事先得到错误的所有