-->

NPE in HandledContributionItem.canExecuteItem

2019-07-26 17:57发布

问题:

I have this little editor with a toolbar contributed by the plugin.xml:

public class MyEditor extends EditorPart {

    public static final String ID = "org.acme.project.MyEditor";

    @Override
    public void init(IEditorSite site, IEditorInput input) throws PartInitException {
        setSite(site);
        setInput(input);
    }

    @Override
    public void createPartControl(Composite parent) {
        final ToolBarManager localToolBarmanager = new ToolBarManager();
        final IMenuService menuService = PlatformUI.getWorkbench().getService(IMenuService.class);
        menuService.populateContributionManager(localToolBarmanager, "toolbar:org.acme.menu");
        localToolBarmanager.createControl(parent);

    }
}

And of course, my plugin.xml has a contribution:

<extension point="org.eclipse.ui.menus">
  <menuContribution allPopups="false" locationURI="toolbar:org.acme.menu">
        <command commandId="org.eclipse.ui.file.saveAll" style="push" />
    </menuContribution>
</extension>

The editor opens, the toolbar gets contributed, everything is fine. When I close the workbench part that was active when I open the editor, I get the following exception:

!ENTRY org.eclipse.e4.ui.workbench.renderers.swt 4 2 2017-10-30 15:12:53.110
!MESSAGE Problems occurred when invoking code from plug-in: "org.eclipse.e4.ui.workbench.renderers.swt".
!STACK 0
java.lang.NullPointerException
    at org.eclipse.e4.ui.workbench.renderers.swt.HandledContributionItem.canExecuteItem(HandledContributionItem.java:443)
    at org.eclipse.e4.ui.workbench.renderers.swt.AbstractContributionItem$4.run(AbstractContributionItem.java:524)
    at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
    at org.eclipse.e4.ui.workbench.renderers.swt.AbstractContributionItem.updateItemEnablement(AbstractContributionItem.java:564)
    at org.eclipse.e4.ui.workbench.renderers.swt.ToolItemUpdater.updateContributionItems(ToolItemUpdater.java:36)
    at org.eclipse.e4.ui.workbench.renderers.swt.ToolBarManagerRenderer.subscribeTopicUpdateToolbarEnablement(ToolBarManagerRenderer.java:295)
    at sun.reflect.GeneratedMethodAccessor32.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.eclipse.e4.core.internal.di.MethodRequestor.execute(MethodRequestor.java:55)
    at org.eclipse.e4.ui.internal.di.UIEventObjectSupplier$UIEventHandler$1.run(UIEventObjectSupplier.java:56)
    at org.eclipse.swt.widgets.RunnableLock.run(RunnableLock.java:35)
    at org.eclipse.swt.widgets.Synchronizer.runAsyncMessages(Synchronizer.java:182)
    at org.eclipse.swt.widgets.Display.runAsyncMessages(Display.java:4211)
    at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3827)

And it's really only the one part that had focus. I can close other parts just fine. This exception leads to the handlers in the toolbar being broken and the toolbar not working anymore.

I found some bugs with that exception: Bug 388516 & Bug 394500

But these were supposedly fixed in 4.2 (and we are using 4.6). Other then that, I can't find anything which might result in weird error messages like that.

Does anyone have an idea how to fix our toolbar?

回答1:

That's one of the stupider E4 bugs. Probably Top 3 for us.

WorkbenchMenuService.populateContributionManager(ContributionManager, String) takes the currently active workbench part to register the menu for. Since toolbars are usually created in IWorkbenchPart.createPartControl(Composite), that means the new part was not yet fully created, and so is not yet the active part.

So toolbars do not work anymore for all views and editors!!!

I found a workaround (that is really ugly, but what are you going to do?) to fix this massive E4 bug. The call to populateContributionManager must be replaced with the following lines:

    final MPart part = getSite().getService(MPart.class);
    String menuLocation = "toolbar:org.acme.menu";

    if (menuService instanceof WorkbenchMenuService) {
        ((WorkbenchMenuService) menuService).populateContributionManager(part, manager, menuLocation);
    } else if (menuService instanceof SlaveMenuService) {
        ((SlaveMenuService) menuService).populateContributionManager(part, manager, menuLocation);
    } else
        throw new UnsupportedOperationException("Do not know how to handle " + menuService); //$NON-NLS-1$