How do I avoid repetition in Java ResourceBundle strings?
- by Trejkaz
We had a lot of strings which contained the same sub-string, from sentences about checking the log or how to contact support, to branding-like strings containing the company or product name. The repetition was causing a few issues for ourselves (primarily typos or copy/paste errors) but it also causes issues in that it increases the amount of text our translator has to translate.
The solution I came up with went something like this:
public class ExpandingResourceBundleControl extends ResourceBundle.Control {
public static final ResourceBundle.Control EXPANDING =
new ExpandingResourceBundleControl();
private ExpandingResourceBundleControl() { }
@Override
public ResourceBundle newBundle(String baseName, Locale locale, String format,
ClassLoader loader, boolean reload)
throws IllegalAccessException, InstantiationException, IOException {
ResourceBundle inner = super.newBundle(baseName, locale, format, loader, reload);
return inner == null ? null : new ExpandingResourceBundle(inner, loader);
}
}
ExpandingResourceBundle delegates to the real resource bundle but performs conversion of {{this.kind.of.thing}} to look up the key in the resources.
Every time you want to get one of these, you have to go:
ResourceBundle.getBundle("com/acme/app/Bundle", EXPANDING);
And this works fine -- for a while.
What eventually happens is that some new code (in our case autogenerated code which was spat out of Matisse) looks up the same resource bundle without specifying the custom control. This appears to be non-reproducible if you write a simple unit test which calls it with and then without, but it occurs when the application is run for real. Somehow the cache inside ResourceBundle ejects the good value and replaces it with the broken one. I am yet to figure out why and Sun's jar files were compiled without debug info so debugging it is a chore.
My questions:
Is there some way of globally setting the default ResourceBundle.Control that I might not be aware of? That would solve everything rather elegantly.
Is there some other way of handling this kind of thing elegantly, perhaps without tampering with the ResourceBundle classes at all?