2011-01-22 19 views
15

我正在使用Hibernate Validator,並希望在錯誤消息中解析類別的名稱。考慮這種簡單的情況:如何使用Hibernate Validator動態解析消息參數?

public class Category { 
    private String name; 
} 

public class Product { 
    @HazardousCategoryConstraint(message = "{haz.cat.error}") 
    private Category category; 
    private String name; 
} 

public class InventoryReport { 
    @Valid 
    private List<Product> products; 
} 


ValidationMessages.properties 
haz.cat.error={name} is a product in the hazardous category list. 

假設我有一個HazardousCategoryConstraint的工作實現。驗證器根據受限名稱列表檢查每個類別的名稱。當我調用驗證(InventoryReport)時,我得到了我期望的錯誤數,除了它們是相同的字符串。我希望將類別的名稱解析爲每封郵件。有人能給我一個動態解析參數的例子,或者告訴我如何去做?

+0

什麼你問的是:如何把錯誤信息字符串的值? - 它是否正確? – Ralph 2011-01-22 15:24:48

+0

@Ralph - 這是正確的,但更具體地說,我希望它是動態的。我有許多具有獨特名稱的類別實例。 – 2011-01-24 21:20:04

回答

10

IMO,簡單的解決方案是創建javax.validation.MessageInterpolator的自定義實現。將主要工作委託給Hibernate Validator的ResourceBundleMessageInterpolator並在CustomMessageInterpolator中進行所需的替換工作。

public class CustomMessageInterpolator extends org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator { 

    private static final Pattern MESSAGE_PARAMETER_PATTERN = Pattern.compile("(\\{[^\\}]+?\\})"); 

    @Override 
    public String interpolate(String message, Context context) { 
     String resolvedMessage = super.interpolate(message, context); 
     resolvedMessage = replacePropertyNameWithPropertyValues(resolvedMessage, context.getValidatedValue()); 
     return resolvedMessage; 
    } 

    private String replacePropertyNameWithPropertyValues(String resolvedMessage, Object validatedValue) { 
     Matcher matcher = MESSAGE_PARAMETER_PATTERN.matcher(resolvedMessage); 
     StringBuffer sb = new StringBuffer(); 

     while (matcher.find()) { 
      String parameter = matcher.group(1); 

      String propertyName = parameter.replace("{", ""); 
      propertyName = propertyName.replace("}", ""); 

      PropertyDescriptor desc = null; 
      try { 
       desc = new PropertyDescriptor(propertyName, validatedValue.getClass()); 
      } catch (IntrospectionException ignore) { 
       matcher.appendReplacement(sb, parameter); 
       continue; 
      } 

      try { 
       Object propertyValue = desc.getReadMethod().invoke(validatedValue); 
       matcher.appendReplacement(sb, propertyValue.toString()); 
      } catch (Exception ignore) { 
       matcher.appendReplacement(sb, parameter); 
      } 
     } 
     matcher.appendTail(sb); 
     return sb.toString(); 
    } 

} 

@Test

public void validate() { 
     Configuration<?> configuration = Validation.byDefaultProvider().configure(); 
     ValidatorFactory validatorFactory = configuration.messageInterpolator(new CustomMessageInterpolator()).buildValidatorFactory(); 
     Validator validator = validatorFactory.getValidator(); 

     Product p = new Product(); 
     Category cat = new Category(); 
     cat.setName("s"); //assume specified name is invalid 
     p.setCategory(cat); 

     Set<ConstraintViolation<Product>> violations = validator.validate(p); 
     for(ConstraintViolation<Product> violation : violations) { 
      System.out.println(violation.getMessage()); 
     } 
    } 

輸出

s is a product in the hazardous category list.