eclipse-efx / efxclipse-rt

Eclipse Public License 1.0
28 stars 29 forks source link

NPE when executing workbench.close() #404

Open MarceloRuiz opened 4 years ago

MarceloRuiz commented 4 years ago

I have a Handler defined to be called when clicking the File>Exit menu:

package sample.mvn.app.handlers;

import org.eclipse.e4.core.di.annotations.Execute;
import org.eclipse.e4.ui.workbench.IWorkbench;

public class AppExitHandler {

    @Execute
    public void execute(final IWorkbench workbench) {
    workbench.close();
    }

}

When the handler is invoked, the application exits but giving a NullPointerException:

May 03, 2020 9:57:26 PM org.eclipse.fx.ui.workbench.renderers.base.BaseMenuRenderer handleHiding
INFO: Model context is null, probably already disposed
May 03, 2020 9:57:26 PM org.eclipse.fx.core.log.internal.ExceptionLogger lambda$1
SEVERE: null
java.lang.NullPointerException
    at javafx.controls/javafx.scene.control.skin.MenuButtonSkinBase.lambda$new$7(MenuButtonSkinBase.java:188)
    at javafx.scene.control.skin.MenuButtonSkinBase$$Lambda$585/0000000000000000.run(Unknown Source)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:428)
    at com.sun.javafx.application.PlatformImpl$$Lambda$185/0000000000000000.run(Unknown Source)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:704)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:427)
    at com.sun.javafx.application.PlatformImpl$$Lambda$184/0000000000000000.run(Unknown Source)
    at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
    at javafx.graphics/com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)
    at javafx.graphics/com.sun.glass.ui.gtk.GtkApplication.lambda$runLoop$11(GtkApplication.java:277)
    at com.sun.glass.ui.gtk.GtkApplication$$Lambda$173/0000000000000000.run(Unknown Source)
    at java.base/java.lang.Thread.run(Thread.java:834)
tomsontom commented 4 years ago

hm the exception is from the JavaFX class what is found at that location? The reason we log it is that efxclipse installs a ExceptionHandler for UncatchedExceptions and routes that through our logging system.

tomsontom commented 4 years ago

there's eg https://bugs.openjdk.java.net/browse/JDK-8244110

MarceloRuiz commented 4 years ago

what is found at that location? Sorry, but I don't understand what you're referencing to. What is "that" location?

there's eg https://bugs.openjdk.java.net/browse/JDK-8244110 Do I understand this correctly and this is a bug and we need to wait for it to be fixed?

tomsontom commented 4 years ago

Well what‘s the code at line 188 in MenuButtonSkinBase?

MarceloRuiz commented 4 years ago

Here is the code so you have the context also (I marked line 188 in the code on the left margin):

    public MenuButtonSkinBase(final C control) {
        super(control);

        if (control.getOnMousePressed() == null) {
            control.addEventHandler(MouseEvent.MOUSE_PRESSED, e -> {
                MenuButtonBehaviorBase behavior = getBehavior();
                if (behavior != null) {
                    behavior.mousePressed(e, behaveLikeButton);
                }
            });
        }

        if (control.getOnMouseReleased() == null) {
            control.addEventHandler(MouseEvent.MOUSE_RELEASED, e -> {
                MenuButtonBehaviorBase behavior = getBehavior();
                if (behavior != null) {
                    behavior.mouseReleased(e, behaveLikeButton);
                }
            });
        }

        /*
         * Create the objects we will be displaying.
         */
        label = new MenuLabeledImpl(getSkinnable());
        label.setMnemonicParsing(control.isMnemonicParsing());
        label.setLabelFor(control);

        arrow = new StackPane();
        arrow.getStyleClass().setAll("arrow");
        arrow.setMaxWidth(Region.USE_PREF_SIZE);
        arrow.setMaxHeight(Region.USE_PREF_SIZE);

        arrowButton = new StackPane();
        arrowButton.getStyleClass().setAll("arrow-button");
        arrowButton.getChildren().add(arrow);

        popup = new ContextMenu();
        popup.getItems().clear();
        popup.getItems().addAll(getSkinnable().getItems());

        getChildren().clear();
        getChildren().addAll(label, arrowButton);

        getSkinnable().requestLayout();

        itemsChangedListener = c -> {
            while (c.next()) {
                popup.getItems().removeAll(c.getRemoved());
                popup.getItems().addAll(c.getFrom(), c.getAddedSubList());
            }
        };
        control.getItems().addListener(itemsChangedListener);

        if (getSkinnable().getScene() != null) {
            ControlAcceleratorSupport.addAcceleratorsIntoScene(getSkinnable().getItems(), getSkinnable());
        }
        control.sceneProperty().addListener((scene, oldValue, newValue) -> {
            if (getSkinnable() != null && getSkinnable().getScene() != null) {
                ControlAcceleratorSupport.addAcceleratorsIntoScene(getSkinnable().getItems(), getSkinnable());
            }
        });

        // Register listeners
        registerChangeListener(control.showingProperty(), e -> {
            if (getSkinnable().isShowing()) {
                show();
            } else {
                hide();
            }
        });
        registerChangeListener(control.focusedProperty(), e -> {
            // Handle tabbing away from an open MenuButton
            if (!getSkinnable().isFocused() && getSkinnable().isShowing()) {
                hide();
            }
            if (!getSkinnable().isFocused() && popup.isShowing()) {
                hide();
            }
        });
        registerChangeListener(control.mnemonicParsingProperty(), e -> {
            label.setMnemonicParsing(getSkinnable().isMnemonicParsing());
            getSkinnable().requestLayout();
        });
        List<Mnemonic> mnemonics = new ArrayList<>();
        registerChangeListener(popup.showingProperty(), e -> {
            if (!popup.isShowing() && getSkinnable().isShowing()) {
                // Popup was dismissed. Maybe user clicked outside or typed ESCAPE.
                // Make sure button is in sync.
                getSkinnable().hide();
            }

            if (popup.isShowing()) {
                boolean showMnemonics = NodeHelper.isShowMnemonics(getSkinnable());
                Utils.addMnemonics(popup, getSkinnable().getScene(), showMnemonics, mnemonics);
            } else {
188 ->      // we wrap this in a runLater so that mnemonics are not removed
                // before all key events are fired (because KEY_PRESSED might have
                // been used to hide the menu, but KEY_TYPED and KEY_RELEASED
                // events are still to be fired, and shouldn't miss out on going
                // through the mnemonics code (especially in case they should be
                // consumed to prevent them being used elsewhere).
                // See JBS-8090026 for more detail.
                Scene scene = getSkinnable().getScene();
                List<Mnemonic> mnemonicsToRemove = new ArrayList<>(mnemonics);
                mnemonics.clear();
                Platform.runLater(() -> mnemonicsToRemove.forEach(scene::removeMnemonic));
            }
        });
    }