2015-06-05 1 views
0

Я смущен о том случае, когда есть несколько аннотаций ограничений на поле, ниже:Несколько ограничений аннотаций путать на Java Bean Validation

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, почему это происходит, что-то еще, что я проигнорировал?

ответ

3

когда @NotNull ограничение нарушается, он не будет продолжать

Это неправильно. Он продолжит проверку всех других ограничений. Дело в том, что валидатор размера рассматривает нулевое значение как приемлемое значение. Причина заключается в том, что, как правило, вы хотите

  • непустое, минимальное значения размера: то применяются оба ограничения
  • или обнуляемое значение, которое должно иметь минимальный размер, если значение присутствует: то используйте только размер.
+0

Да, я был неправ, я просто вижу внешний вид. @JB Низет спасибо. –

2

Вы недопонимаете те валидаторы - they have no guarantee of order, в которых они оцениваются.

По умолчанию ограничения оцениваются без особого порядка, независимо от того, к каким группам они принадлежат.

Так это означает, что либо ваш ACheckили ваш BCheck мог не, или обоих; не определено, какой отказ произойдет в первую очередь.

Если вы хотите, чтобы иметь возможность определить заказ с помощью двух отдельных аннотаций, вам необходимо использовать @GroupSequence, чтобы указать это.

В качестве альтернативы, если вы хотите быстро выйти, то configure the validator to do so.

Validator validator = Validation.byProvider(HibernateValidator.class) 
     .configure() 
     .failFast(true) 
     .buildValidatorFactory() 
     .getValidator(); 

Я бы лично препятствовать такой подход, поскольку это означает, что пользователь, который не может валидаций должен сделать повторен запросы к ресурсу каждый раз, когда одна вещь является неправильным, в отличие от получения все что неправильно фронт.

+0

Да, я был недоразумением. @Makoto спасибо. –