java 如何获取 ConstraintValidatorContext?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15409763/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 19:29:39  来源:igfitidea点击:

How to obtain ConstraintValidatorContext?

javajakarta-eebean-validation

提问by alexsmail

I am writing code that has explicit call to Bean Validation (JSR-303) something like this:

我正在编写显式调用 Bean 验证 (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;


    }


}

Note the line boolean isValid = validator.isValid(str, null);I transfer nullfor ConstraintValidatorContextbecause I found no way to obtain/construct it. In this particular case, this if fine, because there is no use of the ConstraintValidatorContextinternally, but it is obvious a hack. How should I get ConstraintValidatorContext?

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

ADDED

添加

I was asked to provide use-cases. So, for example, I am writting custom validator and I want to reuse exisiting validations. Or I am writting plane Java code as desribed above and I want to reuse exisiting validation.

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

采纳答案by Hardy

The simple answer is you cannot. ConstraintValidatorContextis an interface and there is no Bean Validation API to get an instance like this. You could write your own implementation, but to implement it properly you would have to re-implement a lot of functionality of a Bean Validation provider. Look for example at the Hibernate Validator specific implementation - https://github.com/hibernate/hibernate-validator/blob/master/engine/src/main/java/org/hibernate/validator/internal/engine/constraintvalidation/ConstraintValidatorContextImpl.java

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

That said, I believe your attempt of reuse is misguided. This is not in the indent of Bean Validation and you are ending up with non portable and hard to maintain code. If you want to reuse existing constraints have a look at constraint composition, for example @NotEmpty reusing @NotNull and @Size

也就是说,我相信您的重用尝试是错误的。这不是 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();
    }
} 

回答by user3262600

I recently had exactly the same issue as the OP. However contrary to the accepted answer it is possible to write Unit tests that include the ConstraintValidationContext. This excellent link explains how to do it, http://farenda.com/java/bean-validation-unit-testing/

我最近遇到了与 OP 完全相同的问题。然而,与公认的答案相反,可以编写包含 ConstraintValidationContext 的单元测试。这个优秀的链接解释了如何做到这一点,http://farenda.com/java/bean-validation-unit-testing/

Basically you need to use the ValidatorFactory to obtain a Validator interface, then call validate(c) on that interface, where the parameter c is an instance of the class containing the bean validation annotations. A code example is clearer, code sample taken from the above link.

基本上,您需要使用 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);
  }

}

}

回答by SpaceTrucker

You should declare a group for the constraints you validate in that case. Then you can call the normal validation for that group. See sections 2.1.1.2 and section 3.4 of the spec for group definitions and their semantics. For validating the group, you then just need to call Validator.validate(T Object, Class<?>... groups). There is no need to mess around with the ConstraintValidatorContextin this case.

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