2011-01-22 15 views
15

Hazırda Bekletme Validator kullanıyorum ve kategorinin adını bir hata iletisinde gidermek istiyorum. bu basit senaryoyu düşünün:İleti parametrelerini Hibernate Validator ile dinamik olarak nasıl çözebilirim?

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. 

Ben HazardousCategoryConstraint bir çalışma uygulaması olduğunu varsayalım. Doğrulayıcı, her bir Kategorinin adını, kısıtlanmış adların bir listesiyle kontrol eder. Doğrulama (InventoryReport) çağırdığımda beklediğim hataların sayısını aynı dizeler dışında aldım. Her mesajın kategorisinin adını çözdüğünü görmek isterim. Birisi beni parametrelerini dinamik olarak çözmenin bir örneğine işaret edebilir mi, yoksa nasıl yapılacağını gösterir mi?

+0

Ne sormak: nasıl hata mesajı dizesinde bir değer koymak? -- bu doğru mu? – Ralph

+0

@Ralph - bu doğru, ancak daha spesifik olarak dinamik olmasını istiyorum. Benzersiz isimleri olan birçok kategoriye sahibim. –

+0

Ama mesaja koymak istediğiniz isimler sizin doğrulayıcı tarafından bilinir, değil mi? – Ralph

cevap

10

IMO, basit bir çözüm, javax.validation.MessageInterpolator özel uygulamasının oluşturulmasıdır. Ana işi Hibernate Validator'un ResourceBundleMessageInterpolator'a devredin ve gerekli değiştirme işini CustomMessageInterpolator'da yapın.

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

Çıktı

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

Sabit JPA kullanımı için özel mesaj enterpolator'unu nasıl ayarlayabilirim? – alexsmail

+0

Sadece bir OO olayı: Hazırda Bekletme Validator 'ResourceBundleMessageInterpolator' genişletmek yerine Hibernate internals bağımsız olmak için 'CustomMessageInterpolator' bir delege kullanmak istiyorum. –

İlgili konular