2015-04-22 68 views
2

我正在尝试为this link的答案中的示例创建集合的BV约束验证程序。使用Bean验证验证集合不会正确返回无效元素

public class ConstraintValidatorFactoryImpl implements ConstraintValidatorFactory { 

    private ValidatorContext validatorContext; 

    public ConstraintValidatorFactoryImpl(ValidatorContext nativeValidator) { 
     this.validatorContext = nativeValidator; 
    } 

    public <T extends ConstraintValidator<?, ?>> T getInstance(Class<T> key) { 
     T instance = null; 
     try { 
      instance = key.newInstance(); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 

     if(ValidatorContextAwareConstraintValidator.class.isAssignableFrom(key)) { 
      ValidatorContextAwareConstraintValidator validator = (ValidatorContextAwareConstraintValidator) instance; 
      validator.setValidatorContext(validatorContext); 
     } 

     return instance; 
    } 
} 

这里是验证器。

public class CinCodeValidator implements ConstraintValidator<CinCode, String> { 

    private static Pattern cinCodePattern; 

    public void initialize(CinCode constraintAnnotation) { 
     if (cinCodePattern == null) { 
      cinCodePattern = Pattern.compile("([0-9]{1,5})"); 
     } 
    } 

    public boolean isValid(String value, ConstraintValidatorContext context) { 
     boolean result = false; 
     if (isNotNull(value)) { 
      result = matchCode(value); 
     } 
     if(!result) { 
      context.disableDefaultConstraintViolation(); 
      context.buildConstraintViolationWithTemplate("Invalid Cin code" ).addConstraintViolation(); 
     } 
     return result; 
    } 

    private static boolean isNotNull(Object obj) { 
     return obj != null; 
    } 

    private boolean matchCode(String value) { 
     Matcher matcher = cinCodePattern.matcher(value); 
     return matcher.matches(); 
    } 
} 


public class CollectionElementBean { 
    private String cinCode; 

    @CinCode(message = "This should be a valid CIN code") 
    public String getCinCode() { 
     return cinCode; 
    } 

    public void setCinCode(String cinCode) { 
     this.cinCode = cinCode; 
    } 
} 


public interface ValidatorContextAwareConstraintValidator { 
    void setValidatorContext(ValidatorContext validatorContext); 
} 

验证收集:

public class ValidCollectionValidator implements ConstraintValidator<ValidCollection, Collection>, ValidatorContextAwareConstraintValidator { 

    private static final Logger logger = LoggerFactory.getLogger(ValidCollectionValidator.class); 

    private ValidatorContext validatorContext; 

    private Class<?> elementType; 
    private Class<?>[] constraints; 
    private boolean allViolationMessages; 

    public void setValidatorContext(ValidatorContext validatorContext) { 
     this.validatorContext = validatorContext; 
    } 

    public void initialize(ValidCollection constraintAnnotation) { 
     elementType = constraintAnnotation.elementType(); 
     constraints = constraintAnnotation.constraints(); 
     allViolationMessages = constraintAnnotation.allViolationMessages(); 
    } 

    public boolean isValid(Collection collection, ConstraintValidatorContext context) { 
     boolean valid = true; 
     if (collection == null) { 
      return false; 
     } 

     Validator validator = validatorContext.getValidator(); 
     boolean beanConstrained = validator.getConstraintsForClass(elementType).isBeanConstrained(); 
     for (Object element : collection) { 
      Set<ConstraintViolation<?>> violations = new HashSet<ConstraintViolation<?>>(); 

      if (beanConstrained) { 
       boolean hasValidCollectionConstraint = hasValidCollectionConstraint(elementType); 
       if (hasValidCollectionConstraint) { 
        // elementType has @ValidCollection constraint 
        violations.addAll(validator.validate(element)); 
       } else { 
        violations.addAll(validator.validate(element)); 
       } 
      } else { 
       for (Class<?> constraint : constraints) { 
        String propertyName = constraint.getSimpleName(); 
        propertyName = Introspector.decapitalize(propertyName); 
        violations.addAll(validator.validateValue(CollectionElementBean.class, propertyName, element)); // Here, only failed values get added. 
       } 
      } 

      if (!violations.isEmpty()) { 
       valid = false; 
      } 

      if (allViolationMessages) { 
       for (ConstraintViolation<?> violation : violations) { 
        logger.debug(violation.getMessage()); 
        ConstraintViolationBuilder violationBuilder = context.buildConstraintViolationWithTemplate(violation.getMessage()); 
        violationBuilder.addConstraintViolation(); 
       } 
      } 
     } 
     return valid; 
    } 

    private boolean hasValidCollectionConstraint(Class<?> beanType) { 
     BeanDescriptor beanDescriptor = validatorContext.getValidator().getConstraintsForClass(beanType); 
     boolean isBeanConstrained = beanDescriptor.isBeanConstrained(); 
     if (!isBeanConstrained) { 
      return false; 
     } 
     Set<ConstraintDescriptor<?>> constraintDescriptors = beanDescriptor.getConstraintDescriptors(); 
     for (ConstraintDescriptor<?> constraintDescriptor : constraintDescriptors) { 
      if (constraintDescriptor.getAnnotation().annotationType().getName().equals(ValidCollection.class.getName())) { 
       return true; 
      } 
     } 
     Set<PropertyDescriptor> propertyDescriptors = beanDescriptor.getConstrainedProperties(); 
     for (PropertyDescriptor propertyDescriptor : propertyDescriptors) { 
      constraintDescriptors = propertyDescriptor.getConstraintDescriptors(); 
      for (ConstraintDescriptor<?> constraintDescriptor : constraintDescriptors) { 
       if (constraintDescriptor.getAnnotation().annotationType().getName().equals(ValidCollection.class.getName())) { 
        return true; 
       } 
      } 
     } 
     return false; 
    } 

} 

形式GEO身份证,州数和CIN的名单:

public class FormWithCollection { 
    private List<String> cinCodes; 
    @NotNull 
    @ValidCollection(elementType = String.class, constraints = { CinCode.class }) 
    public List<String> getCinCodes() { 
     return cinCodes; 
    } 
    public void setCinCodes(List<String> cinCodes) { 
     this.cinCodes = cinCodes; 
    } 
    //Same goes for GEO Id and State number  

} 

测试程序:

public class ValidCollectionTest { 
    private ValidatorFactory validatorFactory; 

    @Before 
    public void createValidatorFactory() { 
     validatorFactory = Validation.buildDefaultValidatorFactory(); 
    } 

    private Validator getValidator() { 
     ValidatorContext validatorContext = validatorFactory.usingContext(); 
     validatorContext.constraintValidatorFactory(new ConstraintValidatorFactoryImpl(validatorContext)); 
     Validator validator = validatorContext.getValidator(); 
     return validator; 
    } 

    /** 
    A valid CIN code is 1 to 5 digit numeric. 
    */ 
    @Test  
    public void validateCollectionWithInvalidCIN() { 
     FormWithCollection formWithCollection = new FormWithCollection(); 
     formWithCollection.setCinCode(Arrays.asList("12345", "111a1")); 
     Validator validator = getValidator(); 

     Set<ConstraintViolation<FormWithCollection>> violations = validator.validate(formWithCollection, Default.class); 
     for (ConstraintViolation<FormWithCollection> violation : violations) { 
      System.out.println(violation.getMessage() + "\t" + violation.getInvalidValue()); 
     } 
     Assert.assertEquals(1, violations.size()); // I expect to see just 1 violation as there is only one invalid value "111a1". But 2 violations are returned. 
    } 
} 

在ValidCollectionTest。 java,ConstraintV集合重复迭代以列出所有违规。我试图列出每个violation.getInvalidValue()让用户知道。但getInvalidValue()返回整个集合而不是失败的值。

我想向用户显示无效值,因为我有一个这样的形式:

+-----------+----------+---------+ 
|Geo ID  |State # |CIN  | 
+-----------+----------+---------+ 
|   |   |   | 
+-----------+----------+---------+ 
|   |   |   | 
+-----------+----------+---------+ 
|   |   |   | 
+-----------+----------+---------+ 

凡GEO标识,状态数和CIN三种不同的输入格式。

有没有解决这个问题的方法,只列出失败的值?

回答

0

我不认为你所指的文章中的解决方案是一个好主意。你需要验证一个特定的约束吗?如果是这样,只需创建一个ConstraintValidator<MyConstraint, Collection>。迭代传递的集合并自己验证每个元素。它也将有助于显示你的代码(约束,约束验证等)。或者如果您使用的是Java 8,则可以尝试使用最新的Hibernate Validator 5.2版本,该版本允许使用类型注释,例如List<@MyConstraint String>

+0

感谢您的回复。我现在已经包含了代码。我正在尝试验证成员=> GEO ids列表,状态列表和CIN在ListWithCollection.java中的列表 – bkrish