2011-01-22 29 views
15

Tôi đang sử dụng Trình xác thực Hibernate và muốn giải quyết tên của danh mục trong thông báo lỗi. Hãy xem xét trường hợp đơn giản này:Làm cách nào để tự động giải quyết thông số thư bằng Trình xác thực Hibernate?

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. 

Giả sử rằng tôi đang triển khai thực hiện HazardousCategoryConstraint. Trình xác thực kiểm tra tên của mỗi Danh mục dựa vào danh sách các tên bị hạn chế. Khi tôi gọi validate (InventoryReport), tôi nhận được số lỗi mà tôi mong đợi ngoại trừ chúng là cùng một chuỗi. Tôi muốn xem tên của Danh mục được giải quyết trong mỗi thư. Ai đó có thể chỉ cho tôi một ví dụ về cách giải quyết các thông số động hay chỉ cho tôi cách thực hiện?

+0

gì bạn yêu cầu là: làm thế nào để đặt một giá trị trong chuỗi thông báo lỗi? - điều này có đúng không? – Ralph

+0

@Ralph - đó là chính xác, nhưng cụ thể hơn tôi muốn nó là năng động. Tôi có nhiều trường hợp Danh mục có tên duy nhất. –

+0

Nhưng tên bạn muốn đặt trong thông báo được xác định cho người xác thực của bạn, đúng không? – Ralph

Trả lời

10

IMO, giải pháp đơn giản là tạo triển khai tùy chỉnh javax.validation.MessageInterpolator. Ủy quyền công việc chính cho ResourceBundleMessageInterpolator của Hibernate Validator và thực hiện công việc thay thế theo yêu cầu trong 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()); 
     } 
    } 

Output

s is a product in the hazardous category list. 
+0

Làm thế nào tôi có thể đặt nội suy tin nhắn tùy chỉnh để sử dụng JPA liên tục? – alexsmail

+0

Chỉ là một điều OO: Thay vì mở rộng 'ResourceBundleMessageInterpolator của Hibernate Validator', tôi muốn sử dụng một delegate trong' CustomMessageInterpolator' để độc lập với nội bộ Hibernate. –

Các vấn đề liên quan