I have a problem with displaying开发者_开发技巧 custom ValidationMessages of Hibernate Validator in UTF-8.
For common jsf messages I followed this advice: i18n with UTF-8 encoded properties files in JSF 2.0 appliaction - I created class Text and used it in faces-config.xml. This is working properly.
But this approach is not working with ValidationMessages; special characters are not displayed in UTF-8.
Could anyone give me some advice about this? Thank you very much
I have solved in the same way. Hibernate validator has configuration file in META-INF/validation.xml
Example for validation.xml
<validation-config xmlns="http://jboss.org/xml/ns/javax/validation/configuration"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://jboss.org/xml/ns/javax/validation/configuration">
<message-interpolator>com.mycompany.validation.utf8.UTF8ResourceBundleMessageInterpolator</message-interpolator>
</validation-config>
Implementation for UTF8ResourceBundleMessageInterpolator
public class UTF8ResourceBundleMessageInterpolator extends ResourceBundleMessageInterpolator {
public UTF8ResourceBundleMessageInterpolator() {
super(new UTF8ResourceBundleLocator(ResourceBundleMessageInterpolator.USER_VALIDATION_MESSAGES));
}
}
Implementation for UTF8ResourceBundleLocator (clone of PlatformResourceBundleLocator class with small fix)
public class UTF8ResourceBundleLocator implements ResourceBundleLocator {
private static final Logger logger = LoggerFactory.getLogger(UTF8ResourceBundleLocator.class);
protected static final ResourceBundle.Control UTF8_CONTROL = new UTF8Control();
private final String bundleName;
public UTF8ResourceBundleLocator(String bundleName) {
this.bundleName = bundleName;
}
/**
* Search current thread classloader for the resource bundle. If not found,
* search validator (this) classloader.
*
* @param locale The locale of the bundle to load.
* @return the resource bundle or <code>null</code> if none is found.
*/
@Override
public ResourceBundle getResourceBundle(Locale locale) {
ResourceBundle rb = null;
ClassLoader classLoader = GetClassLoader.fromContext();
if (classLoader != null) {
rb = loadBundle(
classLoader, locale, bundleName
+ " not found by thread local classloader"
);
}
if (rb == null) {
classLoader = GetClassLoader.fromClass(PlatformResourceBundleLocator.class);
rb = loadBundle(
classLoader, locale, bundleName
+ " not found by validator classloader"
);
}
return rb;
}
private ResourceBundle loadBundle(ClassLoader classLoader, Locale locale, String message) {
ResourceBundle rb = null;
try {
rb = ResourceBundle.getBundle(
bundleName, locale,
classLoader, UTF8_CONTROL
);
} catch (MissingResourceException ignored) {
logger.trace(message);
}
return rb;
}
private static class GetClassLoader implements PrivilegedAction<ClassLoader> {
private final Class<?> clazz;
private static ClassLoader fromContext() {
final GetClassLoader action = new GetClassLoader(null);
if (System.getSecurityManager() != null) {
return AccessController.doPrivileged(action);
} else {
return action.run();
}
}
private static ClassLoader fromClass(Class<?> clazz) {
if (clazz == null) {
throw new IllegalArgumentException("Class is null");
}
final GetClassLoader action = new GetClassLoader(clazz);
if (System.getSecurityManager() != null) {
return AccessController.doPrivileged(action);
} else {
return action.run();
}
}
private GetClassLoader(Class<?> clazz) {
this.clazz = clazz;
}
@Override
public ClassLoader run() {
if (clazz != null) {
return clazz.getClassLoader();
} else {
return Thread.currentThread().getContextClassLoader();
}
}
}
}
Where UTF8Control class is the class from i18n with UTF-8 encoded properties files in JSF 2.0 appliaction
If you use the same Resource-Bundle like in https://stackoverflow.com/a/3646601/5072526, you can do this:
Modify the ResourceBundle from that answer, so you have an additional Constructor, that takes a locale:
public I18NUtf8RessourceBundle(Locale locale) {
setParent(ResourceBundle.getBundle(BUNDLE_NAME,
locale, UTF8_CONTROL));
}
Then create a Class ValidationMessages
in the default package:
public class ValidationMessages extends I18NUtf8RessourceBundle{
public ValidationMessages() {
super(null);
}
}
Then make the same Class with a specific Locale (_en, _de, etc.):
public class ValidationMessages_en extends I18NUtf8RessourceBundle{
public ValidationMessages_en() {
super(Locale.ENGLISH);
}
}
Do the same for all your Languages and pass a different Locale each time:
With that, it works, you can even have the same File for the Validation Messages as for the normal translations!
精彩评论