6

我正在编写对 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;


    }


}

注意这一行boolean isValid = validator.isValid(str, null); 我转移nullConstraintValidatorContext因为我没有办法获得/建造它。在这种特殊情况下,这很好,因为内部没有使用ConstraintValidatorContext,但很明显是一个hack。我应该如何获得ConstraintValidatorContext

添加

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

4

3 回答 3

3

我最近遇到了与 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);
  }

}

于 2018-06-13T10:42:08.647 回答
2

简单的答案是你不能。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。爪哇

也就是说,我相信您的重用尝试是错误的。这不在 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();
    }
} 
于 2013-03-15T09:45:49.870 回答
0

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

于 2013-03-14T14:31:08.393 回答