Использование настраиваемого ResourceBundle с Hibernate Validator

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

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

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

my.message=the property {prop} is invalid

есть вызовы для поиска 'prop' в messageSource. Переход в ResourceBundleMessageInterpolator.interpolateMessage Я отмечаю, что javadoc заявляет:

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

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

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

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

Ответ 1

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

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

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

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

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

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

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

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