JDK-8175977 : SplashScreen preventing Platform.exit() from exiting in JavaFX app
  • Type: Bug
  • Component: javafx
  • Sub-Component: window-toolkit
  • Affected Version: 8u121
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • OS: os_x
  • CPU: x86
  • Submitted: 2017-02-22
  • Updated: 2019-03-23
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
tbdUnresolved
Related Reports
Relates :  
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.8.0_121"
Java(TM) SE Runtime Environment (build 1.8.0_121-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.121-b13, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
Darwin myLab.local 16.4.0 Darwin Kernel Version 16.4.0: Thu Dec 22 22:53:21 PST 2016; root:xnu-3789.41.3~3/RELEASE_X86_64 x86_64

A DESCRIPTION OF THE PROBLEM :
If a JavaFX application is launched with parameter -splash:path_to_image, Platform.exit() won't be able to exit the application in a clean way and the System menubar is OSX will stop to be supported.


STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1 - Create a hello world in JavaFX with a menu called "File".
2 - Be sure to have menuBar.setUseSystemMenuBar(true) so the menu will display in MacOS menuBar and Platform.exit() in your exit() or stop() method and add it a QuitHandler.
3 - Run it using java -cp ... , app here will run normally , exit normally and "File" menu will be displayed exactly in the system menu bar.
4 - Run this time with a splash screen , "java -splash:path_to_img -cp ..."

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
1 - A splash screen is displayed before at startup
2 - Menu "File" is displayed in the OSX system menu bar.
3 - When Quit is clicked , application exits without any exception in the log.
ACTUAL -
1 - A splash screen is displayed before at startup
2 - Menu "File" is displayed in the OSX system menu bar.
3 - When 'Quit' menuItem is clicked , application exits with exceptions. 

ERROR MESSAGES/STACK TRACES THAT OCCUR :

If application is launched from the command line as described before , it shows the following exception on exit :

Exception in thread "AppKit Thread" java.lang.IllegalStateException: Not on FX application thread; currentThread = AppKit Thread
	at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:236)
	at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:423)
	at javafx.stage.Window.setShowing(Window.java:921)
	at javafx.stage.Window.hide(Window.java:947)
	at com.sun.javafx.stage.WindowPeerListener.closed(WindowPeerListener.java:100)
	at com.sun.javafx.tk.quantum.GlassWindowEventHandler.run(GlassWindowEventHandler.java:118)
	at com.sun.javafx.tk.quantum.GlassWindowEventHandler.run(GlassWindowEventHandler.java:40)
	at java.security.AccessController.doPrivileged(Native Method)
	at com.sun.javafx.tk.quantum.GlassWindowEventHandler.lambda$handleWindowEvent$423(GlassWindowEventHandler.java:150)
	at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389)
	at com.sun.javafx.tk.quantum.GlassWindowEventHandler.handleWindowEvent(GlassWindowEventHandler.java:148)
	at com.sun.glass.ui.Window.handleWindowEvent(Window.java:1266)
	at com.sun.glass.ui.Window.notifyDestroy(Window.java:1183)


OR the following exceptions if application is launched using install4j :

 31792 ERROR com.idc.util.javafx.SimpleUncaughtExceptionHandler uncaughtException   34 Uncaught exception
java.lang.IllegalStateException: Not on FX application thread; currentThread = JavaFX Application Thread
	at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:236) ~[jfxrt.jar:?]
	at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:423) ~[jfxrt.jar:?]
	at javafx.stage.Window.setShowing(Window.java:921) ~[jfxrt.jar:?]
	at javafx.stage.Window.hide(Window.java:947) ~[jfxrt.jar:?]
	at com.sun.javafx.stage.WindowPeerListener.closed(WindowPeerListener.java:100) ~[jfxrt.jar:?]
	at com.sun.javafx.tk.quantum.GlassWindowEventHandler.run(GlassWindowEventHandler.java:118) ~[jfxrt.jar:?]
	at com.sun.javafx.tk.quantum.GlassWindowEventHandler.run(GlassWindowEventHandler.java:40) ~[jfxrt.jar:?]
	at java.security.AccessController.doPrivileged(Native Method) ~[?:1.8.0_121]
	at com.sun.javafx.tk.quantum.GlassWindowEventHandler.lambda$handleWindowEvent$423(GlassWindowEventHandler.java:150) ~[jfxrt.jar:?]
	at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389) ~[jfxrt.jar:?]
	at com.sun.javafx.tk.quantum.GlassWindowEventHandler.handleWindowEvent(GlassWindowEventHandler.java:148) ~[jfxrt.jar:?]
	at com.sun.glass.ui.Window.handleWindowEvent(Window.java:1266) ~[jfxrt.jar:?]
	at com.sun.glass.ui.Window.notifyDestroy(Window.java:1183) ~[jfxrt.jar:?]
  

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
 ---> HelloWorldApplication.java

package helloworld;

import com.apple.eawt.AppEvent;
import com.apple.eawt.QuitResponse;

import java.security.AccessControlException;
import java.util.Optional;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuBar;
import javafx.scene.control.MenuItem;
import javafx.scene.control.SeparatorMenuItem;
import javafx.scene.control.TextArea;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

/**
 * Sample application.
 * @author me
 */
public class HelloWorldApplication extends Application {
// constants --------------------------------------------------------------------------------
   private static final Logger LOG = LogManager.getLogger();

   /**
    * Running on Mac platform.
    */
   public static final boolean MAC;

   static {
      boolean mac = false;
      try {
         final String osName = System.getProperty("os.name");
         LOG.debug("OS: {}", osName);
         mac = osName != null && osName.toLowerCase().contains("mac");
      } catch (AccessControlException ex) {
         LOG.debug("Cannot determine OS");
      }
      MAC = mac;
   }

// member variables -------------------------------------------------------------------------
   private final Alert mAlert = new Alert(Alert.AlertType.CONFIRMATION);

// methods ----------------------------------------------------------------------------------
   @Override
   public void start(Stage pStage) {
      final BorderPane root = new BorderPane();

      final MenuBar menuBar = new MenuBar();

      final Menu fileMenu = new Menu("_File");
      menuBar.getMenus().add(fileMenu);

      // Exit
      boolean macQuitMenuItem = false;
      if (MAC) {
         final com.apple.eawt.Application application = com.apple.eawt.Application.getApplication();
         try {
            application.setQuitHandler(
               (AppEvent.QuitEvent pEvt, QuitResponse pQuitResponse) -> Platform.runLater(
                  () -> exit(pQuitResponse::cancelQuit)
               )
            );
            macQuitMenuItem = true;

            // occurs when running as untrusted applet
         } catch (AccessControlException ex) {
            LOG.debug("Cannot listen for application quit");
         }
      }
      if (!macQuitMenuItem) {
         fileMenu.getItems().add(new SeparatorMenuItem());

         final MenuItem exitMenuItem = new MenuItem("E_xit");

         exitMenuItem.setOnAction(pEvt -> exit(() -> {}));
         fileMenu.getItems().add(exitMenuItem);
      }


      root.setTop(menuBar);
      root.setCenter(new TextArea("Hello, world!"));

      final Scene scene = new Scene(root, 300, 250);

      pStage.setTitle("Hello World!");
      pStage.setScene(scene);

      mAlert.initOwner(pStage);
      mAlert.setTitle("Confirm Exit");
      mAlert.setHeaderText("Look, a Confirmation Dialog");
      mAlert.setContentText("Are you sure you want to exit?");

      pStage.show();
   }

   public static void main(String[] pArgs) {launch(pArgs);}

   public void exit() {exit(() -> {});}

   public void exit(Runnable pAbortExitRunnable) {
      LOG.info("Exit");
      if (checkUnsavedChanges()) {
         Platform.exit();
      } else {
         pAbortExitRunnable.run();
      }
   }

   private boolean checkUnsavedChanges() {
      final Optional<ButtonType> result = mAlert.showAndWait();
      return result.isPresent() && result.get() == ButtonType.OK;
   }
}


---> pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>idc</groupId>
    <artifactId>Bug125</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>com.yuvimasory</groupId>
            <artifactId>orange-extensions</artifactId>
            <version>1.3.0</version>
        </dependency>

        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>2.8</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.8</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <version>3.0.0</version>
                <executions>
                    <execution>
                        <id>copy-dependencies</id>
                        <phase>initialize</phase>
                        <goals>
                            <goal>copy-dependencies</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>3.0.2</version>
                <configuration>
                    <archive>
                        <index>true</index>
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <mainClass>helloworld.HelloWorldApplication</mainClass>
                        </manifest>
                    </archive>

                </configuration>

            </plugin>
        </plugins>
    </build>
</project>

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Use JavaFX Preloader instead of SplashScreen.


Comments
This may be related to JDK-8088859 and JDK-8089931
04-03-2017

Verified and its reproducible in 8u121. Please find the attached simple testcase . At first, unable to make com.apple.eawt compile on JDK 8, so after adding -XDignore.symbol.file to compiler flags solved it. When ran normally (without splash screen), clicking on FILE->Exit menu working fine: 1. Menu "File" is displayed in the OSX system menu bar. 2. When "File->Exit" is clicked , application exits without any exception in the log. But when ran using splash screen (java -splash:path-to-img -cp....) : Find attached screenshot for the reference (9047815_splash_exception.png) 1. A splash screen is displayed before at startup 2. Menu "File" is displayed in javafx application menuBar, and not in OSX system menu bar. 3. When "File->Exit" is clicked , application exits with the exception. Couldnt test on JDK 9 as JDK internal APIs (com.apple.eawt.Application) are unsupported and private in JDK 9. Moving it to dev team for further evaluation.
28-02-2017