How to obtain ConstraintValidatorContext?

前端 未结 3 759
予麋鹿
予麋鹿 2021-01-13 20:31

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

public class Example {

    @DecimalMin(value = \"0\")
    private         


        
相关标签:
3条回答
  • 2021-01-13 20:57

    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/

    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.

       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);
      }
    

    }

    0 讨论(0)
  • 2021-01-13 21:13

    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 ConstraintValidatorContext in this case.

    0 讨论(0)
  • 2021-01-13 21:15

    The simple answer is you cannot. ConstraintValidatorContext is 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

    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

    @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();
        }
    } 
    
    0 讨论(0)
提交回复
热议问题