У меня есть простой компонент, определяющий учетные данные пользователя в модели регистрационной формы:
public class UserCreds {
@Length(min=1, max=50)
@NotEmpty
private String username;
@Email
private String email;
@NotEmpty
@Length(min=1, max=50)
private String password;
private String passwordConfirm;
... only obvious getters and setters below this line ...
}
Я передаю его экземпляр под атрибутом модели «userCreds», поэтому у меня есть следующий пакет локализации:
NotEmpty.userCreds.username=Username is required
NotEmpty.userCreds.password=Passsword is required
Length.userCreds.username=Username length must be between {2} and {1} symbols
Length.userCreds.password=Password length must be between {2} and {1} symbols
Email.userCreds.email=Ill-formed e-mail address
И это работает!
Проблема здесь: я не хочу использовать эти загадочные заполнители {N}, которые могут время от времени менять свои места (в пакете выше «max» привязан к {1}, а «min» привязан к {2}, который находится в наименее неочевидное позиционирование) я хочу использовать полные имена аннотаций, как в
Length.userCreds.username=Username length must be between {min} and {max} symbols
(что не работает - когда я пытаюсь - получаю исключение java.lang.IllegalArgumentException: can't parse argument number min
)
Как я мог определить сообщение в коде (следующий пример также работает):
@Length(min=1, max=50, message = "Username length must be between {min} and {max} symbols")
@NotEmpty
private String username;
Но когда я определяю его в коде, я теряю способность локализовать сообщение для разных языков.
Что?
ОБНОВЛЕНИЕ 1
После нескольких часов ковыряния в отладчике в моей IDE я обнаружил, что используется следующий класс:
public class BakaMessageSource extends ReloadableResourceBundleMessageSource {
@Override
protected MessageFormat resolveCode(String code, Locale locale) {
/* original implementation *
for (String basename : basenames) {
List<String> filenames = calculateAllFilenames(basename, locale);
for (String filename : filenames) {
PropertiesHolder propHolder = getProperties(filename);
MessageFormat result = propHolder.getMessageFormat(code, locale);
if (result != null) {
return result;
}
}
}
*/
return null;
}
}
Со следующим объявлением spring-servlet.xml:
<bean id="messageSource" class="org.eientei.radiorandom.framework.crutchy.BakaMessageSource"
p:defaultEncoding="UTF-8"
p:alwaysUseMessageFormat="false"
>
<property name="basenames">
<list>
<!-- my application-specific localization bundles -->
<value>classpath:messages/root/errorMessages</value>
<value>classpath:messages/root/langMessages</value>
<value>classpath:messages/user/signupMessages</value>
</list>
</property>
</bean>
вместо оригинального ReloadableResourceBundleMessageSource действительно помогает получать локализованные сообщения с именованными параметрами.
Но я думаю, что обмен классами в этот момент не является правильным решением. Какой из них будет? забастовка>
ОБНОВЛЕНИЕ 2
Я такой идиот. Я забыл сообщение в коде и подумал, что оно правильно интерполировано. Боже. Итак, в алфавитном порядке... думаю, я не могу просить большего.