2015-04-22 74 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