如何获取ConstraintValidatorContext?

时间:2013-03-14 12:49:28

标签: java java-ee bean-validation

我正在编写显式调用Bean Validation(JSR-303)的代码,如下所示:

public class Example {

    @DecimalMin(value = "0")
    private static final String ANNOTATED = "";

    public void isPossitiveNumber(String str){

        ValidatorFactory factory =
             Validation.buildDefaultValidatorFactory();

        ConstraintValidator<DecimalMin, String>
             validator = 
                  factory.getConstraintValidatorFactory().getInstance(
                          DecimalMinValidatorForString.class);


        validator.initialize(
                  ReflectionUtils.findField(getClass(), "ANNOTATED")
                         .getAnnotation(
                          DecimalMin.class));

        boolean isValid = validator.isValid(str, null);

        return isValid;


    }


}

注意布尔值isValid = validator.isValid(str,null); 我为null转移ConstraintValidatorContext因为我找不到获取/构建它的方法。在这种特殊情况下,这很好,因为内部没有使用ConstraintValidatorContext,但很明显是黑客攻击。我应该如何获得ConstraintValidatorContext

ADDED

我被要求提供用例。因此,例如,我正在编写自定义验证器,我想重用现有的验证。或者我正在编写如上所述的平面Java代码,我想重用现有的验证。

3 个答案:

答案 0 :(得分:1)

简单的答案是你不能。 ConstraintValidatorContext 是一个接口,没有Bean Validation API来获取这样的实例。您可以编写自己的实现,但要正确实现它,您必须重新实现Bean Validation提供程序的许多功能。查看Hibernate Validator特定实现的示例 - https://github.com/hibernate/hibernate-validator/blob/master/engine/src/main/java/org/hibernate/validator/internal/engine/constraintvalidation/ConstraintValidatorContextImpl.java

那就是说,我相信你的重用尝试是错误的。这不是Bean Validation的缩进,你最终会得到不可移植且难以维护的代码。如果要重用现有约束,请查看约束组合,例如@NotEmpty重用@NotNull和@Size

@Documented
@Constraint(validatedBy = { })
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Retention(RUNTIME)
@ReportAsSingleViolation
@NotNull
@Size(min = 1)
public @interface NotEmpty {
    String message() default "{org.hibernate.validator.constraints.NotEmpty.message}";

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

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

    /**
     * Defines several {@code @NotEmpty} annotations on the same element.
     */
    @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
    @Retention(RUNTIME)
    @Documented
    public @interface List {
        NotEmpty[] value();
    }
} 

答案 1 :(得分:0)

在这种情况下,您应该为您验证的约束声明一个组。然后,您可以调用该组的正常验证。有关组定义及其语义,请参阅规范的第2.1.1.2节和第3.4节。要验证该组,您只需拨打Validator.validate(T Object, Class<?>... groups)即可。在这种情况下,没有必要使用ConstraintValidatorContext

答案 2 :(得分:0)

我最近和OP有完全相同的问题。但是,与接受的答案相反,可以编写包含ConstraintValidationContext的单元测试。这个优秀的链接解释了如何执行此操作,http://farenda.com/java/bean-validation-unit-testing/

基本上,您需要使用ValidatorFactory来获取Validator接口,然后在该接口上调用validate(c),其中参数c是包含bean验证注释的类的实例。代码示例更清晰,代码示例取自上面的链接。

   public class Player {

   // name have to be 3 chars:
   @Size(min = 3, max = 3)
   private String name;

   // possible score in game:
   @Min(0) @Max(100)
   private int score;

   public Player(String name, int score) {
      this.name = name;
      this.score = score;
   }

   // just for logs
   @Override
   public String toString() {
      return "Player{name='" + name + '\'' + ", score=" + score + '}';
   }
}

public class PlayerValidationTest {
   private static ValidatorFactory validatorFactory;
   private static Validator validator;

   @BeforeClass
   public static void createValidator() {
      validatorFactory = Validation.buildDefaultValidatorFactory();
      validator = validatorFactory.getValidator();
   }

   @AfterClass
   public static void close() {
      validatorFactory.close();
   }

   @Test
   public void shouldDetectInvalidName() {
      //given too short name:
      Player player = new Player("a", 44);

      //when:
      Set<ConstraintViolation<Player>> violations
            = validator.validate(player);

      //then:
      assertEquals(violations.size(), 1);
  }

}