El uso de un ResourceBundle personalizada con Hibernate Validator
-
27-09-2019 - |
Pregunta
Estoy intentando configurar un origen de mensaje personalizado para Hibernate Validator 4.1 a 3.0 primavera. He creado la configuración necesaria:
<!-- 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 la sustitución fichas 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 los estados javadoc:
Ejecuta la interpolación mensaje de acuerdo con el algoritmo especificado en JSR 303.
Nota: Look-ups en paquetes de usuario es recursivo, mientras look-ups en conjunto por defecto no son!
Esto se parece a mí como la recursividad siempre se llevará a cabo por un paquete especificado por el usuario, lo que en efecto no se puede traducir mensajes estándar como el que para el tamaño.
¿Cómo puedo plug-in que mi propia fuente del mensaje y ser capaz de tener parámetros de ser reemplazado en el mensaje?
Solución
Me parece que la recursividad siempre tendrá un lugar para paquete, lo que en efecto lo especificado por el usuario No se puede traducir mensajes estándar al igual que el de 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 aparece dentro de las dos llaves por ejemplo {someText}
en el mensaje es tratado como replacementToken. ResourceBundleMessageInterpolator intenta encontrar el valor coincidente que puede sustituir a la replacementToken en ResourceBundleLocators.
- primero en UserDefinedValidationMessages (que es recursivo),
- entonces en DefaultValidationMessages (que no es recursivo).
Por lo tanto, si se pone un mensaje estándar JSR-303 en, por ejemplo ResourceBundle encargo, validation_erros.properties
, que será sustituido por el mensaje personalizado. Véase a este Ejemplo mensaje de validación estándar NotNull 'no puede ser nulo' ha sido reemplazado por encargo mensaje 'MyNotNullMessage'.
¿Cómo puedo plug-in de mi propio mensaje I la fuente y ser capaz de tener parámetros ser reemplazado en el mensaje?
my.message = la propiedad {prop} es no válido
Después de pasar por ambas ResourceBundleLocators, hallazgos ResourceBundleMessageInterpolator para más replaceTokens en el resolvedMessage (resuelto por ambos haces). Estos replacementToken son nada más que la nombres de los atributos de anotación , si tales replaceTokens se encuentran en el resolvedMessage, son reemplazados por los valores de anotación correspondiente atributos .
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 {};
}
MyNotNullValidator.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