NullPointerException sporadically occurs during plugin startup
Created originally on Bitbucket by colin-hurley (Colin Hurley)
Versions:
- MercurialEclipse 2.8.0-SNAPSHOT (default branch) (presumably can also happen in 2.7.2 release)
- Mercurial 4.3.1
- Eclipse RCP Oxygen 3a
Steps to reproduce:
The exception sporadically happens on its own at Eclipse/plugin startup with unlucky timing.
It is also possible to induce the exception using the debugger and breakpoints:
- Set breakpoint #1 (closed) in
MercurialStatusCache.java
at the first instruction in thereconfigureMembers()
method (e.g. line 1665) - Set breakpoint #2 (closed) in
MercurialStatusCache.java
at the declaration/assignment of the finalrootStatuses
variable (e.g. line 290) - Debug MercurialEclipse
- After both of the breakpoints hit, either step or resume breakpoint #1 (closed) to induce the exception. It is important to leave breakpoint #2 (closed) where it is in order to prevent the initial assignment of the
rootStatuses
variable.
The exception occurs because reconfigureMembers()
is trying to access the rootStatuses
field before it has been assigned. This is somewhat counter-intuitive for a final field, but the problem appears to be that AbstractCache
registers itself as a listener in its constructor. The AbstractCache
constructor executes before the constructor/initialization code in MercurialStatusCache
, so this registration effectively “leaks” the MercurialStatusCache
instance while it is only partially constructed. Thus, even though the rootStatuses
field is declared final, that field still has a value of null
at the time the registration is made by AbstractCache
. The exception is a result of other mechanisms, such as Eclipse preferences, invoking the MercurialStatusCache
instance while it is still in this partially-constructed state.
The solution will likely involve refactoring AbstractCache
and MercurialStatusCache
to perform listener registration only with a fully-constructed object (i.e. after all of the constructors and class initializers have finished executing).
Stacktrace
java.lang.NullPointerException
at com.vectrace.MercurialEclipse.team.cache.MercurialStatusCache.reconfigureMembers(MercurialStatusCache.java:1668)
at com.vectrace.MercurialEclipse.team.cache.AbstractCache$1.propertyChange(AbstractCache.java:77)
at org.eclipse.ui.preferences.ScopedPreferenceStore$3.run(ScopedPreferenceStore.java:350)
at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
at org.eclipse.ui.preferences.ScopedPreferenceStore.firePropertyChangeEvent(ScopedPreferenceStore.java:346)
at org.eclipse.ui.preferences.ScopedPreferenceStore$2.preferenceChange(ScopedPreferenceStore.java:181)
at org.eclipse.core.internal.preferences.EclipsePreferences$2.run(EclipsePreferences.java:848)
at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
at org.eclipse.core.internal.preferences.EclipsePreferences.firePreferenceEvent(EclipsePreferences.java:851)
at org.eclipse.core.internal.preferences.EclipsePreferences.remove(EclipsePreferences.java:958)
at com.vectrace.MercurialEclipse.preferences.PreferenceStoreManager.remove(PreferenceStoreManager.java:58)
at com.vectrace.MercurialEclipse.preferences.PreferenceMigrationTask.run(PreferenceMigrationTask.java:84)
at com.vectrace.MercurialEclipse.preferences.PreferenceInitializer.initializeDefaultPreferences(PreferenceInitializer.java:55)
at org.eclipse.core.internal.preferences.PreferenceServiceRegistryHelper$1.run(PreferenceServiceRegistryHelper.java:298)
at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
at org.eclipse.core.internal.preferences.PreferenceServiceRegistryHelper.runInitializer(PreferenceServiceRegistryHelper.java:301)
at org.eclipse.core.internal.preferences.PreferenceServiceRegistryHelper.applyRuntimeDefaults(PreferenceServiceRegistryHelper.java:131)
at org.eclipse.core.internal.preferences.PreferencesService.applyRuntimeDefaults(PreferencesService.java:370)
at org.eclipse.core.internal.preferences.DefaultPreferences.applyRuntimeDefaults(DefaultPreferences.java:222)
at org.eclipse.core.internal.preferences.DefaultPreferences.load(DefaultPreferences.java:276)
at org.eclipse.core.internal.preferences.EclipsePreferences.create(EclipsePreferences.java:370)
at org.eclipse.core.internal.preferences.EclipsePreferences.internalNode(EclipsePreferences.java:623)
at org.eclipse.core.internal.preferences.EclipsePreferences.node(EclipsePreferences.java:766)
at org.eclipse.core.internal.preferences.AbstractScope.getNode(AbstractScope.java:38)
at org.eclipse.core.runtime.preferences.DefaultScope.getNode(DefaultScope.java:74)
at org.eclipse.ui.preferences.ScopedPreferenceStore.getDefaultPreferences(ScopedPreferenceStore.java:237)
at org.eclipse.ui.preferences.ScopedPreferenceStore.getPreferenceNodes(ScopedPreferenceStore.java:268)
at org.eclipse.ui.preferences.ScopedPreferenceStore.internalGet(ScopedPreferenceStore.java:418)
at org.eclipse.ui.preferences.ScopedPreferenceStore.getString(ScopedPreferenceStore.java:462)
at com.vectrace.MercurialEclipse.team.MercurialUtilities.getPreference(MercurialUtilities.java:128)
at com.vectrace.MercurialEclipse.DefaultConfiguration.getPreference(DefaultConfiguration.java:47)
at com.vectrace.MercurialEclipse.commands.HgClients.getPreference(HgClients.java:99)
at com.vectrace.MercurialEclipse.team.MercurialUtilities.getHGExecutable(MercurialUtilities.java:112)
at com.vectrace.MercurialEclipse.team.MercurialUtilities.isHgExecutableCallable(MercurialUtilities.java:92)
at com.vectrace.MercurialEclipse.team.MercurialUtilities.getHGExecutable(MercurialUtilities.java:148)
at com.vectrace.MercurialEclipse.MercurialEclipsePlugin.checkHgInstallation(MercurialEclipsePlugin.java:202)
at com.vectrace.MercurialEclipse.MercurialEclipsePlugin$1.run(MercurialEclipsePlugin.java:151)
at org.eclipse.core.internal.jobs.Worker.run(Worker.java:55)