Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 315282

Summary: NPE in SaveHandler
Product: [Eclipse Project] e4 Reporter: Paul Webster <pwebster>
Component: UIAssignee: Oleg Besedin <ob1.eclipse>
Status: RESOLVED FIXED QA Contact:
Severity: normal    
Priority: P3 CC: bokowski, ob1.eclipse, remy.suen
Version: 1.0Flags: pwebster: review+
bokowski: review+
Target Milestone: 1.0 RC3   
Hardware: All   
OS: All   
Whiteboard:
Attachments:
Description Flags
Add canExecute call to MenuItemRenderer
none
Possible patch
none
Javadoc patch none

Description Paul Webster CLA 2010-06-01 15:20:01 EDT
I have an @CanExecute method in the SaveHandler:

@CanExecute
boolean canExecute(@Named(IServiceConstants.ACTIVE_PART) MDirtyable dirtyable)

It's being called with a null value, even though it doesn't have @Optional in front of it.

I thought @Optional was necessary to allow null for a parameter (I may be wrong here).

My canExecute(*) failed with an NPE:

!ENTRY org.eclipse.osgi 4 0 2010-06-01 15:17:05.006
!MESSAGE Application error
!STACK 1
org.eclipse.e4.core.di.InjectionException: java.lang.NullPointerException
	at org.eclipse.e4.core.internal.di.MethodRequestor.execute(MethodRequestor.java:49)
	at org.eclipse.e4.core.internal.di.InjectorImpl.invokeUsingClass(InjectorImpl.java:178)
	at org.eclipse.e4.core.internal.di.InjectorImpl.invoke(InjectorImpl.java:159)
	at org.eclipse.e4.core.contexts.ContextInjectionFactory.invoke(ContextInjectionFactory.java:101)
	at org.eclipse.e4.core.commands.internal.HandlerServiceImpl.canExecute(HandlerServiceImpl.java:94)
	at org.eclipse.e4.workbench.ui.renderers.swt.MenuItemRenderer.setEnabled(MenuItemRenderer.java:200)
	at org.eclipse.e4.workbench.ui.renderers.swt.MenuItemRenderer.createWidget(MenuItemRenderer.java:185)
	at org.eclipse.e4.ui.workbench.swt.internal.PartRenderingEngine.createWidget(PartRenderingEngine.java:436)
	at org.eclipse.e4.ui.workbench.swt.internal.PartRenderingEngine.createGui(PartRenderingEngine.java:330)
	at org.eclipse.e4.ui.workbench.swt.internal.PartRenderingEngine.createGui(PartRenderingEngine.java:388)
	at org.eclipse.e4.workbench.ui.renderers.swt.SWTPartRenderer.processContents(SWTPartRenderer.java:57)
	at org.eclipse.e4.ui.workbench.swt.internal.PartRenderingEngine.createGui(PartRenderingEngine.java:342)
	at org.eclipse.e4.ui.workbench.swt.internal.PartRenderingEngine.createGui(PartRenderingEngine.java:388)
	at org.eclipse.e4.workbench.ui.renderers.swt.SWTPartRenderer.processContents(SWTPartRenderer.java:57)
	at org.eclipse.e4.ui.workbench.swt.internal.PartRenderingEngine.createGui(PartRenderingEngine.java:342)
	at org.eclipse.e4.workbench.ui.renderers.swt.WBWRenderer.processContents(WBWRenderer.java:456)
	at org.eclipse.e4.ui.workbench.swt.internal.PartRenderingEngine.createGui(PartRenderingEngine.java:342)
	at org.eclipse.e4.ui.workbench.swt.internal.PartRenderingEngine.createGui(PartRenderingEngine.java:388)
	at org.eclipse.e4.ui.workbench.swt.internal.PartRenderingEngine$3.run(PartRenderingEngine.java:493)
	at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:332)
	at org.eclipse.e4.ui.workbench.swt.internal.PartRenderingEngine.run(PartRenderingEngine.java:457)
	at org.eclipse.e4.workbench.ui.internal.E4Workbench.createAndRunUI(E4Workbench.java:102)
	at org.eclipse.ui.internal.Workbench$3.run(Workbench.java:534)
	at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:332)
	at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:520)
	at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:149)
	at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:115)
	at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:196)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:110)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:79)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:369)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:179)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:48)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37)
	at java.lang.reflect.Method.invoke(Method.java:600)
	at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:619)
	at org.eclipse.equinox.launcher.Main.basicRun(Main.java:574)
	at org.eclipse.equinox.launcher.Main.run(Main.java:1407)
	at org.eclipse.equinox.launcher.Main.main(Main.java:1383)
Caused by: java.lang.NullPointerException
	at org.eclipse.e4.ui.internal.workbench.handlers.SaveHandler.canExecute(SaveHandler.java:30)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:48)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37)
	at java.lang.reflect.Method.invoke(Method.java:600)
	at org.eclipse.e4.core.internal.di.MethodRequestor.execute(MethodRequestor.java:42)
	... 39 more
Comment 1 Paul Webster CLA 2010-06-01 15:21:01 EDT
Created attachment 170684 [details]
Add canExecute call to MenuItemRenderer

I added enablement to the MenuItem renderer and then launched a clean 4.0 SDK.

PW
Comment 2 Oleg Besedin CLA 2010-06-02 10:05:58 EDT
The "null" is a valid value in the context; if a "null" value is set in the context, it will be used in injection.

In this case ActivePartLookupFunction sets the value of "e4ActivePart" to "null" due to the following code:

 window = (MContext) context.get(MApplication.class.getName());
	if (window == null) {
		return null;
	}

The value is used when invoking SaveHandler's
 canExecute(@Named(IServiceConstants.ACTIVE_PART) MDirtyable dirtyable)
Comment 3 Brian de Alwis CLA 2010-06-02 14:36:33 EDT
I'm seeing this exact same behaviour for the first time too.
Comment 4 Oleg Besedin CLA 2010-06-02 15:03:41 EDT
Created attachment 170861 [details]
Possible patch

One possible solution is to have IContextFunction return IInjector.NOT_A_VALUE instead of null.
Comment 5 Oleg Besedin CLA 2010-06-02 15:06:09 EDT
(In reply to comment #4)
> Possible patch
By the way, that only going to work if consumers are never supposed to see active part being null.
Comment 6 Eric Moffatt CLA 2010-06-02 15:44:19 EDT
What about a workbench window with no open perspectives? I think that *should* result in 'activePart' == null...
Comment 7 Oleg Besedin CLA 2010-07-21 13:45:33 EDT
Created attachment 174888 [details]
Javadoc patch 

So, null is a valid value for the IServiceConstants.ACTIVE_PART.

(From the context/DI side, there is a difference between "null" value and no value. In general, "null" is a valid value for a variable and, if set, will be injected.)

I've looked at all references to the ACTIVE_PART in SDK and they all seem to properly react to null values in the ACTIVE_PART.

The only change needed is a Javadoc change specifying that "null" is a valid value for the IServiceConstants.ACTIVE_PART.
Comment 8 Oleg Besedin CLA 2010-07-21 13:46:52 EDT
Boris, Paul, can you review? The change is only in Javadoc, might as well do it now.
Comment 9 Oleg Besedin CLA 2010-07-22 14:15:20 EDT
Fixed in CVS Head.