2010-11-23 15 views
12

Estoy intentando configurar un origen de mensajes personalizado para Hibernate Validator 4.1 hasta Spring 3.0. He creado la configuración necesaria:Uso de un paquete de recursos personalizado con Hibernate Validator

<!-- JSR-303 --> 
<bean id="validator" 
    class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"> 
    <property name="validationMessageSource" ref="messageSource"/> 
</bean> 

Las traducciones se sirven de mi fuente del mensaje, pero parece que los tokens de reemplazo en los mensajes mismos se buscan en la fuente del mensaje, es decir, para un

:
my.message=the property {prop} is invalid 

hay llamadas para buscar 'prop' en el messageSource. Al entrar en ResourceBundleMessageInterpolator.interpolateMessage observo que el javadoc afirma:

Se ejecuta la interpolación mensaje de acuerdo con el algoritmo especificado en JSR 303.

Nota: Look-ups en paquetes de usuario es recursivo mientras que mirar planos en conjunto por defecto ¡no son!

Esto me parece que la recursión siempre tendrá lugar para un paquete especificado por el usuario, por lo que en efecto no puedo traducir mensajes estándar como el de Tamaño.

¿Cómo puedo conectar mi propio origen de mensajes y poder tener parámetros reemplazados en el mensaje?

+0

No entiendo por qué el hecho se toma el paquete específico del usuario primero le impide traducir los mensajes de '@ size'. ¿Podrías elaborar? –

+0

@Grzegorz - no se trata de un paquete específico para el usuario que, en mi opinión, es el problema, sino el hecho de que los tokens se resuelven recursivamente en el paquete de usuario. –

Respuesta

17

Esta me parece la recursividad siempre tendrá lugar para un paquete especificado por el usuario , lo que en efecto me no puede traducir mensajes estándar como el que para el tamaño.

ResourceBundleMessageInterpolator de Hibernate Validator crear dos instancias de ResourceBundleLocator (es decir PlatformResourceBundleLocator) una para mensajes de validación definida por el usuario - userResourceBundleLocator y el otro para JSR-303 mensajes de validación estándar - defaultResourceBundleLocator.

Cualquier texto que aparezca dentro de dos llaves, p. Ej. {someText} en el mensaje se trata como reemplazoToken. ResourceBundleMessageInterpolator intenta encontrar el valor coincidente que puede reemplazar el reemplazoToken en ResourceBundleLocators.

  1. primero en UserDefinedValidationMessages (que es recursivo),
  2. entonces en DefaultValidationMessages (que no es recursivo).

Por lo tanto, si se pone un mensaje estándar JSR-303 en la costumbre ResourceBundle decir, validation_erros.properties, que será sustituido por el mensaje personalizado. Ver en este EXAMPLE El mensaje de validación de NotNull estándar 'puede no ser nulo' ha sido reemplazado por el mensaje personalizado 'MyNotNullMessage'.

¿Cómo plug-in que mi propia fuente del mensaje y ser capaz de tener parámetros ser reemplazados en el mensaje?
mi.= mensaje de la propiedad {prop} es inválida

Después de pasar por ambas ResourceBundleLocators, ResourceBundleMessageInterpolator encuentra para más replaceTokens en el resolvedMessage (resueltos por ambos haces). Estos ReplaceToken no son más que los nombres de los atributos de Annotation, si tales replaceTokens se encuentran en resolMessage, se reemplazan por los valores de los atributos de Anotación coincidentes.

ResourceBundleMessageInterpolator.java [Línea 168, 4.1.0.Final]

resolvedMessage = replaceAnnotationAttributes(resolvedMessage, annotationParameters); 

Proporcionar un ejemplo para reemplazar {prop} con valor en aduana, espero que le ayudará a ....

MyNotNull.java

@Constraint(validatedBy = {MyNotNullValidator.class}) 
public @interface MyNotNull { 
    String propertyName(); //Annotation Attribute Name 
    String message() default "{myNotNull}"; 
    Class<?>[] groups() default { }; 
    Class<? extends Payload>[] payload() default {}; 
} 

MyNotNullVa lidator.java

public class MyNotNullValidator implements ConstraintValidator<MyNotNull, Object> { 
    public void initialize(MyNotNull parameters) { 
    } 

    public boolean isValid(Object object, ConstraintValidatorContext constraintValidatorContext) { 
     return object != null; 
    } 
} 

User.java

class User { 
    private String userName; 

    /* whatever name you provide as propertyName will replace {propertyName} in resource bundle */ 
    // Annotation Attribute Value 
    @MyNotNull(propertyName="userName") 
    public String getUserName() { 
     return userName; 
    } 
    public void setUserName(String userName) { 
     this.userName = userName; 
    } 
} 

validation_errors.properties

notNull={propertyName} cannot be null 

prueba

public void test() { 
    LocalValidatorFactoryBean factory = applicationContext.getBean("validator", LocalValidatorFactoryBean.class); 
    Validator validator = factory.getValidator(); 
    User user = new User("James", "Bond"); 
    user.setUserName(null); 
    Set<ConstraintViolation<User>> violations = validator.validate(user); 
    for(ConstraintViolation<User> violation : violations) { 
     System.out.println("Custom Message:- " + violation.getMessage()); 
    } 
} 

salida

Custom Message:- userName cannot be null 
+0

Esa es una respuesta muy completa. Voy a validarlo mañana a primera hora. ¡Gracias! –

+0

Bueno, el problema no estaba allí, sino en mi implementación de MessageSource, que no devolvió 'nulo' a las claves que no se encontraron, sino a la clave misma. Una vez que corregí eso todo funcionó. Pero tu respuesta me puso en el camino correcto, así que es un ganador. –

Cuestiones relacionadas