This is not exactly trivial.
For one just clearing the ResourceBundle
via clearCache()
doesn't always yield the desired results. Often you need at least also try to clear using the context class loader:
ResourceBundle.clearCache(Thread.currentThread().getContextClassLoader());
This however will still not reload the resource bundle defined in a faces-config.xml file. At least the Mojarra JSF 1.2 implementation privately caches the resource bundle internally. This happens in:
FacesContext -> Application -> associate (ApplicationAssociate) -> resourceBundles (Map<String, ApplicationResourceBundle>()) -> resources (Map<Locale, ResourceBundle>)
It's possible to clear this cache via reflection (at the end of the day, it's just an entry in a Map), or you might wanna replace the Application. Both are not things you normally do lightheartedly.
Purely for development you could use JRebel, which probably already has knowledge of Mojarra and most likely does the reflection trick mentioned above.
After some experimenting, I came to the following code which does the trick on JBoss AS 5/JSF 1.2. It does tie your code to Mojarra (imports sun packages) and can break with any upgrade because of reflective tricks being used. But anyway, this is the code:
public static void reloadBundle() {
ResourceBundle.clearCache(Thread.currentThread().getContextClassLoader());
ApplicationResourceBundle appBundle = ApplicationAssociate.getCurrentInstance().getResourceBundles().get("your_bundle_name");
Map<Locale, ResourceBundle> resources = getFieldValue(appBundle, "resources");
resources.clear();
}
@SuppressWarnings("unchecked")
private static <T> T getFieldValue(Object object, String fieldName) {
try {
Field field = object.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
return (T) field.get(object);
} catch (Exception e) {
return null;
}
}
(replace the getFieldValue helper method with your own favorite reflective util if necessary and sprinkle with exception and null handlers where appropriate)
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…