Использование собственного ResourceBundle с Hibernate Validator - PullRequest
12 голосов
/ 23 ноября 2010

Я пытаюсь настроить собственный источник сообщений для Hibernate Validator 4.1 до Spring 3.0. Я настроил необходимую конфигурацию:

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

Переводы выполняются из моего источника сообщений, но кажется, что токены замены в самих сообщениях ищутся в источнике сообщений, то есть для:

my.message=the property {prop} is invalid

есть вызовы для поиска 'prop' в источнике сообщений. Переходя к ResourceBundleMessageInterpolator.interpolateMessage Замечу, что в Javadoc говорится:

Запускает интерполяцию сообщения в соответствии с алгоритмом, указанным в JSR 303.

Примечание: Поиск в пользовательских пакетах является рекурсивным, тогда как поиск в стандартных пакетах - нет!

Мне кажется, что рекурсия всегда будет выполняться для указанного пользователем пакета, поэтому я не могу перевести стандартные сообщения, например, для Size.

Как я могу подключить свой собственный источник сообщений и иметь возможность замены параметров в сообщении?

1 Ответ

18 голосов
/ 23 ноября 2010

Это выглядит как рекурсия всегда будет иметь место для указанный пользователем пакет, поэтому в действительности я не могу перевести стандартные сообщения как тот для размера.

ResourceBundleMessageInterpolator Hibernate Validator создает два экземпляра ResourceBundleLocator (т. Е. PlatformResourceBundleLocator), один для сообщений проверки UserDefined - userResourceBundleLocator, а другой для стандартных сообщений проверки JSR-303 - defaultResourceBundleoc. *

Любой текст, который появляется в двух фигурных скобках, например {someText} в сообщении рассматривается как замена токена. ResourceBundleMessageInterpolator пытается найти соответствующее значение, которое может заменить replaceToken в ResourceBundleLocators.

  1. сначала в UserDefinedValidationMessages (который является рекурсивным),
  2. затем в DefaultValidationMessages (что НЕ является рекурсивным).

Итак, если вы поместите стандартное сообщение JSR-303 в пользовательский ResourceBundle, скажем, validation_erros.properties, оно будет заменено вашим пользовательским сообщением. См. В этом ПРИМЕРЕ Стандартное сообщение проверки NotNull «Возможно, не пусто» заменено пользовательским сообщением «MyNotNullMessage».

Как мне добавить собственное сообщение? источник и иметь возможность иметь параметры заменить в сообщении?
my.message = свойство {prop} недействительный

После прохождения обоих ResourceBundleLocators ResourceBundleMessageInterpolator находит дополнительные replaceTokens в resolvedMessage (разрешается в обоих пакетах). Эти replaceToken - не что иное, как имена атрибутов аннотации , если такие replaceToken находятся в resolvedMessage, они заменяются значениями соответствующих атрибутов аннотации .

ResourceBundleMessageInterpolator.java [строка 168, 4.1.0.Final]

resolvedMessage = replaceAnnotationAttributes( resolvedMessage, annotationParameters );

Предоставляя пример замены {prop} пользовательским значением, я надеюсь, это поможет вам ....

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 

Test

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

выход

Custom Message:- userName cannot be null
...