2011-01-22 11 views
15

Sto usando Hibernate Validator e vorrei risolvere il nome della categoria in un messaggio di errore. Si consideri questo scenario semplice:Come posso risolvere dinamicamente i parametri dei messaggi con 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. 

Supponiamo che io ho un'implementazione di lavoro di HazardousCategoryConstraint. Il validatore controlla il nome di ciascuna categoria in base a un elenco di nomi limitati. Quando chiamo convalida (InventoryReport) ottengo il numero di errori che mi aspetto tranne che sono la stessa stringa. Mi piacerebbe vedere il nome della categoria risolto in ogni messaggio. Qualcuno può indicarmi un esempio su come risolvere i parametri in modo dinamico o mostrarmi come?

+0

Quello che chiedi è: come mettere un valore nella stringa di messaggio di errore? -- è corretto? – Ralph

+0

@ Ralph - è corretto, ma più specificamente voglio che sia dinamico. Ho molte istanze di categorie con nomi univoci. –

+0

Ma i nomi che vuoi inserire nel messaggio sono noti al tuo validatore, giusto? – Ralph

risposta

10

IMO, la soluzione semplice è creare un'implementazione personalizzata di javax.validation.MessageInterpolator. Delegare il lavoro principale a Hibernate Validator ResourceBundleMessageInterpolator ed eseguire i lavori di sostituzione richiesti in 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()); 
     } 
    } 

uscita

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

Come posso impostare l'interpolatore personalizzato dei messaggi per l'utilizzo costante del JPA? – alexsmail

+0

Solo una cosa OO: invece di estendere 'ResourceBundleMessageInterpolator' di Hibernate Validator preferirei usare un delegato in 'CustomMessageInterpolator' per essere indipendente dagli interni di Hibernate. –

Problemi correlati