2

Problem:

  • Running JavaFX application jar fails though the main javafx.application.Application class runs successfully showing a GUI window.

What I have:

  • IntelliJ IDEA Community Edition 2021.2.1
  • Liberica Full JDK 11.0.12+7 x86 64 bit for Windows(Already includes JavaFX)
  • Windows 10 Home 64bit

Project structure(IDE generated, not modified):


    main
        ├───java
        │   │   module-info.java
        │   │
        │   ├───com
        │   │   └───tejasb
        │   │       └───test
        │   │               HelloApplication.java
        │   │               HelloController.java
        │   │
        │   └───META-INF
        │           MANIFEST.MF
        │
        └───resources
            └───com
                └───tejasb
                    └───test
                            hello-view.fxml

Source code:

  • HelloApplication.java

    package com.tejasb.test;
    
    import javafx.application.Application;
    import javafx.fxml.FXMLLoader;
    import javafx.scene.Scene;
    import javafx.stage.Stage;
    
    import java.io.IOException;
    
    public class HelloApplication extends Application {
        @Override
        public void start(Stage stage) throws IOException {
            FXMLLoader fxmlLoader = new FXMLLoader(HelloApplication.class.getResource("hello-view.fxml"));
            Scene scene = new Scene(fxmlLoader.load(), 320, 240);
            stage.setTitle("Hello!");
            stage.setScene(scene);
            stage.show();
        }
    
        public static void main(String[] args) {
            launch();
        }
    }

  • HelloController.java

    package com.tejasb.test;
    
    import javafx.fxml.FXML;
    import javafx.scene.control.Label;
    
    public class HelloController {
        @FXML
        private Label welcomeText;
    
        @FXML
        protected void onHelloButtonClick() {
            welcomeText.setText("Welcome to JavaFX Application!");
        }
    }

  • hello-view.fxml

    <?xml version="1.0" encoding="UTF-8"?>
    
    <?import javafx.geometry.Insets?>
    <?import javafx.scene.control.Label?>
    <?import javafx.scene.layout.VBox?>
    
    <?import javafx.scene.control.Button?>
    <VBox alignment="CENTER" spacing="20.0" xmlns:fx="http://javafx.com/fxml"
          fx:controller="com.tejasb.test.HelloController">
        <padding>
            <Insets bottom="20.0" left="20.0" right="20.0" top="20.0"/>
        </padding>
    
        <Label fx:id="welcomeText"/>
        <Button text="Hello!" onAction="#onHelloButtonClick"/>
    </VBox>

  • module-info.java

    module com.tejasb.test {
        requires javafx.controls;
        requires javafx.fxml;
    
    
        opens com.tejasb.test to javafx.fxml;
        exports com.tejasb.test;
    }

  • MANIFEST.MF

    Manifest-Version: 1.0
    Main-Class: com.tejasb.test.HelloApplication

Exception stack trace(when application jar is ran):


    Exception in Application start method
    java.lang.reflect.InvocationTargetException
            at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
            at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
            at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
            at java.base/java.lang.reflect.Method.invoke(Method.java:566)
            at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:464)
            at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:363)
            at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
            at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
            at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
            at java.base/java.lang.reflect.Method.invoke(Method.java:566)
            at java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:1051)
    Caused by: java.lang.RuntimeException: Exception in Application start method
            at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:900)
            at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(LauncherImpl.java:195)
            at java.base/java.lang.Thread.run(Thread.java:829)
    Caused by: java.lang.IllegalStateException: Location is not set.
            at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2459)
            at javafx.fxml/javafx.fxml.FXMLLoader.load(FXMLLoader.java:2435)
            at com.tejasb.test.HelloApplication.start(HelloApplication.java:14)
            at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:846)
            at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:455)
            at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:428)
            at java.base/java.security.AccessController.doPrivileged(Native Method)
            at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:427)
            at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
            at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
            at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174)
            ... 1 more
    Exception running application com.tejasb.test.HelloApplication

Content of application jar:


    Test.jar
    │   module-info.class
    │
    ├───com
    │   └───tejasb
    │       └───test
    │               HelloApplication.class
    │               HelloController.class
    │
    ├───META-INF
    │       MANIFEST.MF
    │
    └───resources
        └───com
            └───tejasb
                └───test
                        hello-view.fxml

Steps to reproduce problem:

  1. Create project in IntelliJ IDEA with project structure as above
  2. Create new run configuration as Application
    • Set Name, JDK/JRE, -cp from drop down menu and main class as com.tejasb.test.HelloApplication
  3. Go to Project structure>Project settings>Artifacts
    • Click + then JAR>From modules with dependencies...
    • Set Main class as com.tejasb.test.HelloApplication and select copy to the output directory and link via manifest
    • Click OK then on the right side
    • Right click .jar and select Create directory and set name as resources
    • Then right click created directory and select Add copy of>Directory content and select src>main>resources directory (from project)
    • Click OK
  4. Click Run button(application should run successfully showing a window with a button in it)
  5. Now, click Build>Build artifacts...>build(this should build na application jar file at your specified location)
  6. Finally, when this generated jar is ran from console, it doesn't work, throws above exception.

What I have tried:

  • Setting this

    FXMLLoader fxmlLoader = new FXMLLoader(HelloApplication.class.getResource("hello-view.fxml"));

to this


    FXMLLoader fxmlLoader = new FXMLLoader(HelloApplication.class.getResource("/hello-view.fxml"));

this throws the same exception as above even in step 4(Of Steps to reproduce problem) and step 5(Of Steps to reproduce problem) is as it was.

  • Also, tried to use HelloApplication.class.getClassLoader().getResource("hello-view.fxml") and HelloApplication.class.getClassLoader().getResource("/hello-view.fxml") and what not.... But, the jar throws the same exception.

Any help on this will be appreciated. Thanks

dev.tejasb
  • 73
  • 10

1 Answers1

1

An impressive amount of work went into creating this question.

Your problem is that there should not be a directory called resources in your jar.

Instead, hello-view.fxml should end up in the same location in the jar as HelloApplication.

You don’t need a / in the resource lookup.

I don’t know how to fix your resource packaging with your current build method.

I’d recommend using a build tool such as Maven instead of the IDEs built-in artifact creation. I think there might be tutorials for that at openjfx.io. With your current directory structure Maven would automatically place all output files in the correct location of the artifact jar.


If you really did want to keep a folder called resources in your jar (which would be highly unusual and not recommended), then you could just leave it as is and lookup your fxml using the path /resources/com/tejasb/test/hello-view.fxml. Note the asker replied in comments that this method did not work.

jewelsea
  • 150,031
  • 14
  • 366
  • 406
  • Thanks for looking into the question. Just tried to use `/resources/com/tejasb/test/hello-view.fxml` but same exception. – dev.tejasb Sep 15 '21 at 06:56
  • Hmm based on the info in your question I would expect it to work, if your resource lookup is HelloApplication.class.getResource. If you are using a class loader to load the resource it is [more complicated](https://stackoverflow.com/a/68913233/1155209) – jewelsea Sep 15 '21 at 07:24
  • I guess I still recommend changing the build system and ensuring the resource ends up in the correct jar location rather than leaving it as is and trying to get it to work using a resources directory in the jar. – jewelsea Sep 15 '21 at 07:30
  • I'm already using Gradle as project's build system. – dev.tejasb Sep 15 '21 at 07:57
  • I think steps 3 and 5 are ideas build system not gradle. Maybe I’ll try it later when I have a PC and some time. – jewelsea Sep 15 '21 at 08:24
  • I added those steps because Gradle generated jar was also not working – dev.tejasb Sep 15 '21 at 08:46
  • @dev.tejasb Assuming a standard Gradle Java project, the `resources` directory should not be included in the built JAR. Were you getting the _same_ error when trying to execute the JAR built by Gradle? – Slaw Sep 15 '21 at 23:33