Here’s a tip for initializing your plugins or any other singleton-like repository only when needed.
Consider a code like this:
if (isConfigurable()) {
Bundle bundleCopy = bundle;
Preferences[] preferencesCopy = new Preferences[1];
preferencesCopy[0] = new org.eclipse.core.internal.
preferences.legacy.PreferenceForwarder(
this, bundleCopy.getSymbolicName());
return preferencesCopy;
}
return null;
Do you see what’s wrong there?
The problem is that if your #isConfigurable is always FALSE then your code still:
- loads PreferencesForwarder class
- initializes all PreferencesForwarder’s static variables
- forces Preferences plugin to load
Always, if possible and makes sense, isolate your class loading into a simple Runnable inner class if there is some static init or plugin activation trigger involved!
Then the code would become:
if (isConfigurable()) {
final Bundle bundleCopy = bundle;
final Preferences[] preferencesCopy = new Preferences[1];
Runnable innerCall = new Runnable() {
public void run() {
preferencesCopy[0] = new org.eclipse.core.internal.
preferences.legacy.PreferenceForwarder(
this, bundleCopy.getSymbolicName());
}
};
innerCall.run();
}
return null;
When you think of it – this pattern is somewhat similar to the singleton pattern implementation – the one of the very few thread-safe and fast singleton patterns that is bugfree and truly lazy!
Quoting wonderful singleton impl from wikipedia:
public class Singleton {
private Singleton() {}
private static class SingletonHolder {
private final static Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
(OK, to be fully honest, since java1.5 you can also trust volatile flags but – trust noone, use the old stuff:P)
For the reference, the PreferencesForwarder example was taken from the org.eclipse.core.runtime.Plugin#getPluginPreferences class and modified a bit.
UPDATE: This post is not fully correct! Never assume something to be true even if it comes from a trustworthy source like eclipse core runtime source. Please see the comments for explanation!


RSS
LinkedIn
Facebook
3 Comments
In what circumstances do you think that PreferenceForwarder will load from the first example
if (isConfigurable()) {
Bundle bundleCopy = bundle;
Preferences[] preferencesCopy = new Preferences[1];
preferencesCopy[0] = new org.eclipse.core.internal.
preferences.legacy.PreferenceForwarder(
this, bundleCopy.getSymbolicName());
return preferencesCopy;
}
return null;
My understanding is that classloading on most JVMs is so lazy that it will only happen if the condition is evaluated to true. A few tests on different JVMs (Sun 1.4.2, 5, 6 and IBM 1.4.2, 6) with -verbose:class confirmed this behavior for me.
It is not a big deal, but I am a little concerned with adding complexity (although not that much) for no reason.
Mark: Haha! How embarrassing, you were right
Plugin source code has a comment regarding this and it was clearly misleading:
// Performance: isolate PreferenceForwarder into
// an inner class so that it mere presence
// won’t force the PreferenceForwarder class
// to be loaded (which triggers Preferences
// plugin activation).
True, of course it makes sense that class load happens only when it’s actually needed.
Now I don’t see any reason why this Runnable is in #getPluginPreferences after all.
Sometimes respective source code like eclipse runtime is so trustworthy that one stops thinking if it’s really correct