0

i tried to start a new project using OpenJFX modular with Maven. I followed this: https://openjfx.io/openjfx-docs/ (Go to JavaFX with Maven -> Modular with Maven) but gets an Exceptetion in Application start method.

Error:

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:567)
    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:567)
    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:830)
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 org.openjfx/org.openjfx.App.loadFXML(App.java:31)
    at org.openjfx/org.openjfx.App.start(App.java:20)
    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(AccessController.java:391)
    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 org.openjfx.App

pom.xml:

<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/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.openjfx</groupId>
    <artifactId>Oblig1</artifactId>
    <version>1.0-SNAPSHOT</version>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-controls</artifactId>
            <version>13</version>
        </dependency>
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-fxml</artifactId>
            <version>13</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
            <version>3.8.0</version>
            <configuration>
                <release>11</release>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-maven-plugin</artifactId>
            <version>0.0.1</version>
            <configuration>
                <mainClass>org.openjfx.App</mainClass>
            </configuration>
        </plugin>
        </plugins>
    </build>
</project>

app.java

package org.openjfx;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

import java.io.IOException;

/**
 * JavaFX App
 */
public class App extends Application {

    private static Scene scene;

    @Override
    public void start(Stage stage) throws IOException {
        scene = new Scene(loadFXML("/org.openjfx/primary"));
        stage.setScene(scene);
        stage.show();
    }

    static void setRoot(String fxml) throws IOException {
        scene.setRoot(loadFXML(fxml));
    }

    private static Parent loadFXML(String fxml) throws IOException {
        FXMLLoader fxmlLoader = new FXMLLoader(App.class.getResource(fxml + ".fxml"));
        return fxmlLoader.load();
    }

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

}

primary.fxml:

<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Button?>
<?import javafx.geometry.Insets?>

<VBox alignment="CENTER" spacing="20.0" xmlns="http://javafx.com/javafx/8.0.171" 
xmlns:fx="http://javafx.com/fxml/1" fx:controller="kristoffer.PrimaryController">
   <children>
      <Label text="Primary View" />
      <Button fx:id="primaryButton" text="Switch to Secondary View" onAction="#switchToSecondary"/>
   </children>
   <padding>
      <Insets bottom="20.0" left="20.0" right="20.0" top="20.0" />
   </padding>
</VBox>

PrimaryController.java:

package org.openjfx;

import java.io.IOException;
import javafx.fxml.FXML;

public class PrimaryController {

}

secondary.fxml:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Button?>
<?import javafx.geometry.Insets?>

<VBox alignment="CENTER" spacing="20.0" 
xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" 
fx:controller="org.openjfx.SecondaryController">
    <children>
        <Label text="Secondary View" />
        <Button fx:id="secondaryButton" text="Switch to Primary View" 
onAction="#switchToPrimary" />
    </children>
    <padding>
        <Insets bottom="20.0" left="20.0" right="20.0" top="20.0" />
    </padding>
</VBox>

SecondaryController.java:

package org.openjfx;

import java.io.IOException; 
import javafx.fxml.FXML;

public class SecondaryController {

    @FXML
    private void switchToPrimary() throws IOException {
        App.setRoot("PrimaryController");
    }
}

Directorary:

    src
        main
            java
                org.openjfx
                    App.java
                    PrimaryController.java
                    SecondaryController.java
            resources 
                org.openjfx
                    primary.fxml
                    secondary.fxml

jar -tf Oblig1.jar:

I think it might be something with the link in the FXML Loader, i have seen other people having similar issues(like this one), but my directorary has the resources folder unlike theirs. Any help is appreciated, thanks.

  • Yes, please fix the project structure first, and if the error persists you will have to add your Controller code. Looks like your controller is missing `@FXML URL location;`. – Axel Feb 20 '20 at 13:59
  • Yeah, i forgot main. Sorry about that. Also added the controller classes to the question – Kristoffervt Feb 20 '20 at 15:07
  • What do you get if you run `jar -tf` with the correct jar file name (whatever it is; it's probably under a `target` folder somewhere)? – James_D Feb 20 '20 at 15:13

1 Answers1

1

The error message

java.lang.IllegalStateException: Location is not set.

means that the URL you provided to the FXMLLoader constructor was null. The Class.getResource(...) method silently returns null if the resource specified cannot be found.

This is happening because the resource name you're providing to your loadFXML method, and ultimately to App.class.getResource(...) is incorrect. The value you provide to Class.getResource(...) is a resource name, the details of which are documented here.

The resource name is formed from "the fully qualified name of the package of the class, but convert all periods (.) to slashes (/)" (see below). It's impossible to know exactly what's going wrong without at least seeing the structure of the buid folder and/or jar file, but it should probably be

scene = new Scene(loadFXML("/org/openjfx/primary"));

Since your FXML files and the class from which you are executing this code are in the same package, you can probably also get away with just

scene = new Scene(loadFXML("primary"));

Some pertinent parts of that documentation:

Resources, names, and contexts

A resource is identified by a string consisting of a sequence of substrings, delimited by slashes (/), followed by a resource name. Each substring must be a valid Java identifier. The resource name is of the form shortName or shortName.extension. Both shortName and extension must be Java identifiers.

The name of a resource is independent of the Java implementation; in particular, the path separator is always a slash (/). However, the Java implementation controls the details of how the contents of the resource are mapped into a file, database, or other object containing the actual resource.

The interpretation of a resource name is relative to a class loader instance. Methods implemented by the ClassLoader class do this interpretation.

...

Resource Names

A common convention for the name of a resource used by a class is to use the fully qualified name of the package of the class, but convert all periods (.) to slashes (/), and add a resource name of the form name.extension. To support this, and to simplify handling the details of system classes (for which getClassLoader returns null), the class Class provides two convenience methods that call the appropriate methods in ClassLoader.

The resource name given to a Class method may have an initial starting "/" that identifies it as an "absolute" name. Resource names that do not start with a "/" are "relative".

So "/org.openjfx/primary" is not a valid resource name, because "org.openjfx" is not a valid Java identifier.

In your structure, note that org.openjfx is not a folder, but a package. The IDE and build tool will convert this to a folder hierarchy on the file system and ultimately inside the jar file, with the package-subpackage structure being replaced by folders and subfolders. So in your source code structure, you will have a "java" folder with "org" subfolder, "openjfx" sub-subfolder, and in there the Java source files for classes in the org.openjfx package. In the "resources" folder, you will also have an "org" subfolder, an "openjfx" sub-subfolder, and in there the resource files you created (including the FMXL file).

The build tool (either Maven or just your IDE) recognizes specific source folders; these are configured in your case to include "java" and "resources". When the app is built, the union of the structures under the source folders is recreated in the build target; here this just results in a single org folder and openjfx subfolder. Any Java source files are compiled to class files; any other files are merely copied. Finally the whole thing is bundled into a jar file (which is essentially just a zip archive).

If you find the jar file on the file system (by default Maven will place it in a folder called "target", which is alongside your "src" folder), you can examine its contents with

jar -tf Oblig1-1.0-SNAPSHOT.jar

(I think that Oblig1-1.0-SNAPSHOT.jar is the name of the generated jar file, but obviously adjust that if necessary). You should see the folder structure I outlined, and the output should include

/org/openjfx/App.class
/org/openjfx/PrimaryController.class
/org/openjfx/SecondaryController.class
/org/openjfx/primary.fxml
/org/openjfx/secondary.fxml

(The same structure should exist under the target/classes folder, though again the folder naming and location depends on your Maven setup.)

As an aside, you really should not use org.openjfx for your own package names and Maven group ids; use something specific to yourself or your organization.

James_D
  • 201,275
  • 16
  • 291
  • 322
  • Hi, I recreated the whole project from scratch but with Kristoffer instead of org.openjfx. And therefore scene = new Scene(loadFXML("/Kristoffer/primary"));. I still get the same error. I also added the result of jar -tf Oblig1.jar to the question above which doesn't include any of the files you mentioned. Any more ideas? Thanks – Kristoffervt Feb 20 '20 at 15:13
  • @whybother The output from `jar -tf` just says you have the wrong jar file name. What happens if you run it with the correct name? – James_D Feb 20 '20 at 15:15
  • I am not sure what that name would be, this is the target folder: https://imgur.com/a/ISIIVAN – Kristoffervt Feb 20 '20 at 15:27
  • @whybother That makes the issue fairly clear: the FXML files are not getting deployed. Not sure why... that is a Maven config issue. Somehow "resources" is not being recognized as a source folder. – James_D Feb 20 '20 at 15:32