-
Notifications
You must be signed in to change notification settings - Fork 121
Validate document availability after connect() to diagnose null document NPE #2019
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
- Add null check in BundleInputContext.createModel() to handle case when document is not yet available - Add defensive null check in AbstractEditingModel.getInputStream() to prevent NPE - Both changes ensure graceful handling of timing/race conditions during editor initialization Co-authored-by: vogella <[email protected]>
- Allow BundleModel to be created even when document is null - Add explanatory comments about the defensive null handling strategy - The null check in AbstractEditingModel.getInputStream() ensures graceful degradation Co-authored-by: vogella <[email protected]>
|
I have a bad feeling that this is treating a symptom of a problem but not fixing the problem. I.e., won't the editor come up empty? |
|
@copilot can you check what are the possible cause for the document being null at this place? Checking for null itself is not really what we want here. Maybe an update from a wrong thread or code is accessed while the editor is actually already disposed or similar, so I would think analyze and compare the different call sites might reveal something. |
Good point. I'll analyze the call sites and check for threading/disposal issues. Looking at the code, I found that:
The issue might be a race condition between:
Or it could be that
You're absolutely right. My fix treats the symptom but doesn't address the root cause. After investigating, I found that:
I need to investigate WHY connect() is not making the document available. This could be due to:
I'm reverting my changes and will investigate the actual root cause. |
Instead of treating the NPE symptom, validate that the document is available after connect() and throw a descriptive CoreException if not. This helps identify the root cause: - File deleted/moved during editor initialization - Race condition with workspace events - Document provider failing silently The CoreException will be logged with context about which input failed, making it easier to diagnose the actual issue. Co-authored-by: laeubi <[email protected]>
| throw new CoreException(new org.eclipse.core.runtime.Status( | ||
| org.eclipse.core.runtime.IStatus.ERROR, | ||
| "org.eclipse.pde.ui", //$NON-NLS-1$ | ||
| "Document not available after connecting to document provider for input: " + fEditorInput.getName())); //$NON-NLS-1$ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this substantially improve the situation? To me it seems like we are not trading a NullPointerException for a a CoreException?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Furthermore calling the new Status constructor can be replaced by the simpler Status.error() factory:
| throw new CoreException(new org.eclipse.core.runtime.Status( | |
| org.eclipse.core.runtime.IStatus.ERROR, | |
| "org.eclipse.pde.ui", //$NON-NLS-1$ | |
| "Document not available after connecting to document provider for input: " + fEditorInput.getName())); //$NON-NLS-1$ | |
| throw new CoreException(Status.error("Document not available after connecting to document provider for input: " + fEditorInput.getName())); //$NON-NLS-1$ |
Problem
Users experience intermittent
NullPointerExceptionwhen opening MANIFEST.MF files in Eclipse PDE:This occurs "on a regular basis" and requires restarting Eclipse to resolve, indicating a timing/race condition during editor initialization.
Root Cause Analysis
After investigating the issue, the problem is that
getDocumentProvider().getDocument(input)returnsnulleven afterconnect()is called. According to theIDocumentProvidercontract, the document should be available afterconnect()succeeds. The null document can occur due to:CoreExceptionAll
InputContextimplementations are vulnerable to this issue as they assume document is non-null afterconnect().Solution
Instead of treating the symptom with null checks everywhere, the fix validates that
connect()actually succeeded and provides diagnostic information:InputContext.create()Added validation immediately after
fDocumentProvider.connect()to check if the document is available. IfgetDocument()returnsnull, throws a descriptiveCoreExceptionwith the input name and context about possible causes.This approach:
Behavior After Fix
When the document is unavailable after
connect():CoreExceptionis thrown with descriptive error messagecreate()fModelremainsnullTesting
SchemaInputContextand other implementations show that null model is a valid stateImpact
InputContext.create()InputContextsubclasses (Bundle, Plugin, Build, etc.)Fixes #2018
Original prompt
This section details on the original issue you should resolve
<issue_title>NPE while trying to open the MANIFEST.MF</issue_title>
<issue_description>On a regular basis I get the NPE from below, restarting Eclipse fixes that. Refreshing the project explorer for the affected resources does not make a difference.
java.lang.NullPointerException: Cannot invoke "org.eclipse.jface.text.IDocument.get()" because "document" is null
at org.eclipse.pde.internal.core.text.AbstractEditingModel.getInputStream(AbstractEditingModel.java:162)
at org.eclipse.pde.internal.core.text.AbstractEditingModel.load(AbstractEditingModel.java:121)
at org.eclipse.pde.internal.ui.editor.plugin.BundleInputContext.createModel(BundleInputContext.java:87)
at org.eclipse.pde.internal.ui.editor.context.InputContext.create(InputContext.java:165)
at org.eclipse.pde.internal.ui.editor.plugin.BundleInputContext.(BundleInputContext.java:64)
at org.eclipse.pde.internal.ui.editor.plugin.ManifestEditor.createResourceContexts(ManifestEditor.java:264)
at org.eclipse.pde.internal.ui.editor.PDEFormEditor.createInputContexts(PDEFormEditor.java:229)
at org.eclipse.pde.internal.ui.editor.PDEFormEditor.createPages(PDEFormEditor.java:270)
at org.eclipse.ui.part.MultiPageEditorPart.createPartControl(MultiPageEditorPart.java:387)
at org.eclipse.ui.internal.e4.compatibility.CompatibilityPart.createPartControl(CompatibilityPart.java:160)
at org.eclipse.ui.internal.e4.compatibility.CompatibilityEditor.createPartControl(CompatibilityEditor.java:98)
at org.eclipse.ui.internal.e4.compatibility.CompatibilityPart.create(CompatibilityPart.java:367)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at org.eclipse.e4.core.internal.di.MethodRequestor.execute(MethodRequestor.java:58)
at org.eclipse.e4.core.internal.di.InjectorImpl.processAnnotated(InjectorImpl.java:1037)
at org.eclipse.e4.core.internal.di.InjectorImpl.processAnnotated(InjectorImpl.java:998)
at org.eclipse.e4.core.internal.di.InjectorImpl.internalInject(InjectorImpl.java:142)
at org.eclipse.e4.core.internal.di.InjectorImpl.internalMake(InjectorImpl.java:401)
at org.eclipse.e4.core.internal.di.InjectorImpl.make(InjectorImpl.java:319)
at org.eclipse.e4.core.contexts.ContextInjectionFactory.make(ContextInjectionFactory.java:203)
at org.eclipse.e4.ui.internal.workbench.ReflectionContributionFactory.createFromBundle(ReflectionContributionFactory.java:90)
at org.eclipse.e4.ui.internal.workbench.ReflectionContributionFactory.doCreate(ReflectionContributionFactory.java:59)
at org.eclipse.e4.ui.internal.workbench.ReflectionContributionFactory.create(ReflectionContributionFactory.java:42)
at org.eclipse.ui.internal.WorkbenchContributionFactory.create(WorkbenchContributionFactory.java:46)
at org.eclipse.e4.ui.workbench.renderers.swt.ContributedPartRenderer.createWidget(ContributedPartRenderer.java:133)
at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.createWidget(PartRenderingEngine.java:987)
at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.safeCreateGui(PartRenderingEngine.java:658)
at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.safeCreateGui(PartRenderingEngine.java:762)
at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine$2.run(PartRenderingEngine.java:726)
at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:47)
at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.createGui(PartRenderingEngine.java:710)
at org.eclipse.e4.ui.internal.workbench.PartServiceImpl.lambda$0(PartServiceImpl.java:105)
at org.eclipse.e4.ui.services.internal.events.UIEventHandler.lambda$0(UIEventHandler.java:38)
at org.eclipse.swt.widgets.Synchronizer.syncExec(Synchronizer.java:183)
at org.eclipse.ui.internal.UISynchronizer.syncExec(UISynchronizer.java:136)
at org.eclipse.swt.widgets.Display.syncExec(Display.java:5994)
at org.eclipse.e4.ui.workbench.swt.DisplayUISynchronize.syncExec(DisplayUISynchronize.java:34)
at org.eclipse.e4.ui.services.internal.events.UIEventHandler.handleEvent(UIEventHandler.java:38)
at org.eclipse.equinox.internal.event.EventHandlerWrapper.handleEvent(EventHandlerWrapper.java:206)
at org.eclipse.equinox.internal.event.EventHandlerTracker.dispatchEvent(EventHandlerTracker.java:201)
at org.eclipse.equinox.internal.event.EventHandlerTracker.dispatchEvent(EventHandlerTracker.java:1)
at org.eclipse.osgi.framework.eventmgr.EventManager.dispatchEvent(EventManager.java:230)
at org.eclipse.osgi.framework.eventmgr.ListenerQueue.dispatchEventSynchronous(ListenerQueue.java:151)
at org.eclipse.equinox.internal.event.EventAdminImpl.dispatchEvent(EventAdminImpl.java:132)
at org.eclipse.equinox.internal.event.EventAdminImpl.sendEvent(EventAdminImpl.java:73)
at org.eclipse.equinox.internal.event.EventComponent.sendEvent(EventComponent.java:48)
at org.eclipse.e4.ui.services.interna...
Fixes #2018
💬 Share your feedback on Copilot coding agent for the chance to win a $200 gift card! Click here to start the survey.