Loading resources files in Java 11

(Andres Almiray) #1

I’ve taken the task of migrating the Ikonli build from Java 8 to Java11/JavaFX11. While most of the changes required are explained at https://guides.gradle.org/building-java-9-modules/ I’m experiencing some trouble with the run task provided by the application plugin.

Running the application from the command line (using gradlew run) yields the following error on screen

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:834)
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.kordamp.ikonli.sampler.javafx/org.kordamp.ikonli.sampler.javafx.Sampler.start(Sampler.java:81)
        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)
Exception running application org.kordamp.ikonli.sampler.javafx.Sampler

This is because an FXML resource file was not found. The source tree is set as

subprojects/sampler-javafx/
├── sampler-javafx.gradle
└── src
    └── main
        ├── java
        │   ├── module-info.java
        │   └── org
        │       └── kordamp
        │           └── ikonli
        │               └── sampler
        │                   └── javafx
        │                       └── Sampler.java
        └── resources
            └── org
                └── kordamp
                    └── ikonli
                        └── sampler
                            └── javafx
                                ├── sampler.css
                                └── sampler.fxml

The code that throws the error is

URL location = getClass().getResource("sampler.fxml");
FXMLLoader fxmlLoader = new FXMLLoader(location);

Printing out the value of location yields null, which means the resource can’t be found in the module path (?).

All sources available at https://github.com/aalmiray/ikonli. Running with

------------------------------------------------------------
Gradle 4.10.2
------------------------------------------------------------

Build time:   2018-09-19 18:10:15 UTC
Revision:     b4d8d5d170bb4ba516e88d7fe5647e2323d791dd

Kotlin DSL:   1.0-rc-6
Kotlin:       1.2.61
Groovy:       2.4.15
Ant:          Apache Ant(TM) version 1.9.11 compiled on March 23 2018
JVM:          11 (Oracle Corporation 11+28)
OS:           Mac OS X 10.13.6 x86_64
2 Likes

(Christian Stein) #2

How does the command line look like? The line that is generated for the run target … by the application plugin?

0 Likes

(Andres Almiray) #3

Here it is in its full glory

Starting process 'command '/Library/Java/JavaVirtualMachines/jdk-11.jdk/Contents/Home/bin/java''. Working directory: /Users/aalmiray/dev/github/ikonli/subprojects/sampler-javafx Command: /Library/Java/JavaVirtualMachines/jdk-11.jdk/Contents/Home/bin/java --module-path /Users/aalmiray/dev/github/ikonli/subprojects/sampler-javafx/build/classes/java/main:/Users/aalmiray/dev/github/ikonli/subprojects/sampler-javafx/build/resources/main:/Users/aalmiray/dev/github/ikonli/subprojects/ikonli-javafx/build/libs/ikonli-javafx-11.0.0-SNAPSHOT.jar:/Users/aalmiray/dev/github/ikonli/subprojects/ikonli-dashicons-pack/build/libs/ikonli-dashicons-pack-11.0.0-SNAPSHOT.jar:/Users/aalmiray/dev/github/ikonli/subprojects/ikonli-devicons-pack/build/libs/ikonli-devicons-pack-11.0.0-SNAPSHOT.jar:/Users/aalmiray/dev/github/ikonli/subprojects/ikonli-entypo-pack/build/libs/ikonli-entypo-pack-11.0.0-SNAPSHOT.jar:/Users/aalmiray/dev/github/ikonli/subprojects/ikonli-elusive-pack/build/libs/ikonli-elusive-pack-11.0.0-SNAPSHOT.jar:/Users/aalmiray/dev/github/ikonli/subprojects/ikonli-feather-pack/build/libs/ikonli-feather-pack-11.0.0-SNAPSHOT.jar:/Users/aalmiray/dev/github/ikonli/subprojects/ikonli-fontawesome-pack/build/libs/ikonli-fontawesome-pack-11.0.0-SNAPSHOT.jar:/Users/aalmiray/dev/github/ikonli/subprojects/ikonli-fontawesome5-pack/build/libs/ikonli-fontawesome5-pack-11.0.0-SNAPSHOT.jar:/Users/aalmiray/dev/github/ikonli/subprojects/ikonli-fontelico-pack/build/libs/ikonli-fontelico-pack-11.0.0-SNAPSHOT.jar:/Users/aalmiray/dev/github/ikonli/subprojects/ikonli-foundation-pack/build/libs/ikonli-foundation-pack-11.0.0-SNAPSHOT.jar:/Users/aalmiray/dev/github/ikonli/subprojects/ikonli-hawconsfilled-pack/build/libs/ikonli-hawconsfilled-pack-11.0.0-SNAPSHOT.jar:/Users/aalmiray/dev/github/ikonli/subprojects/ikonli-hawconsstroke-pack/build/libs/ikonli-hawconsstroke-pack-11.0.0-SNAPSHOT.jar:/Users/aalmiray/dev/github/ikonli/subprojects/ikonli-icomoon-pack/build/libs/ikonli-icomoon-pack-11.0.0-SNAPSHOT.jar:/Users/aalmiray/dev/github/ikonli/subprojects/ikonli-ionicons-pack/build/libs/ikonli-ionicons-pack-11.0.0-SNAPSHOT.jar:/Users/aalmiray/dev/github/ikonli/subprojects/ikonli-ionicons4-pack/build/libs/ikonli-ionicons4-pack-11.0.0-SNAPSHOT.jar:/Users/aalmiray/dev/github/ikonli/subprojects/ikonli-ligaturesymbols-pack/build/libs/ikonli-ligaturesymbols-pack-11.0.0-SNAPSHOT.jar:/Users/aalmiray/dev/github/ikonli/subprojects/ikonli-maki-pack/build/libs/ikonli-maki-pack-11.0.0-SNAPSHOT.jar:/Users/aalmiray/dev/github/ikonli/subprojects/ikonli-maki2-pack/build/libs/ikonli-maki2-pack-11.0.0-SNAPSHOT.jar:/Users/aalmiray/dev/github/ikonli/subprojects/ikonli-mapicons-pack/build/libs/ikonli-mapicons-pack-11.0.0-SNAPSHOT.jar:/Users/aalmiray/dev/github/ikonli/subprojects/ikonli-material-pack/build/libs/ikonli-material-pack-11.0.0-SNAPSHOT.jar:/Users/aalmiray/dev/github/ikonli/subprojects/ikonli-materialdesign-pack/build/libs/ikonli-materialdesign-pack-11.0.0-SNAPSHOT.jar:/Users/aalmiray/dev/github/ikonli/subprojects/ikonli-metrizeicons-pack/build/libs/ikonli-metrizeicons-pack-11.0.0-SNAPSHOT.jar:/Users/aalmiray/dev/github/ikonli/subprojects/ikonli-octicons-pack/build/libs/ikonli-octicons-pack-11.0.0-SNAPSHOT.jar:/Users/aalmiray/dev/github/ikonli/subprojects/ikonli-openiconic-pack/build/libs/ikonli-openiconic-pack-11.0.0-SNAPSHOT.jar:/Users/aalmiray/dev/github/ikonli/subprojects/ikonli-paymentfont-pack/build/libs/ikonli-paymentfont-pack-11.0.0-SNAPSHOT.jar:/Users/aalmiray/dev/github/ikonli/subprojects/ikonli-runestroicons-pack/build/libs/ikonli-runestroicons-pack-11.0.0-SNAPSHOT.jar:/Users/aalmiray/dev/github/ikonli/subprojects/ikonli-themify-pack/build/libs/ikonli-themify-pack-11.0.0-SNAPSHOT.jar:/Users/aalmiray/dev/github/ikonli/subprojects/ikonli-typicons-pack/build/libs/ikonli-typicons-pack-11.0.0-SNAPSHOT.jar:/Users/aalmiray/dev/github/ikonli/subprojects/ikonli-weathericons-pack/build/libs/ikonli-weathericons-pack-11.0.0-SNAPSHOT.jar:/Users/aalmiray/dev/github/ikonli/subprojects/ikonli-websymbols-pack/build/libs/ikonli-websymbols-pack-11.0.0-SNAPSHOT.jar:/Users/aalmiray/dev/github/ikonli/subprojects/ikonli-zondicons-pack/build/libs/ikonli-zondicons-pack-11.0.0-SNAPSHOT.jar:/Users/aalmiray/.gradle/caches/modules-2/files-2.1/org.openjfx/javafx-fxml/11/e0f5bb81e21054b59f2ebfa727d40a90ee0260d3/javafx-fxml-11-mac.jar:/Users/aalmiray/.gradle/caches/modules-2/files-2.1/org.openjfx/javafx-controls/11/e3a24a14e8732abc6dc173f15872dc63e2a32e16/javafx-controls-11-mac.jar:/Users/aalmiray/.gradle/caches/modules-2/files-2.1/org.openjfx/javafx-controls/11/58d961774262ec972bf304e16c154a8e18c2050b/javafx-controls-11.jar:/Users/aalmiray/.gradle/caches/modules-2/files-2.1/org.openjfx/javafx-swing/11/6fd6f4e3c5f59fa30ca61204877101ed978005aa/javafx-swing-11-mac.jar:/Users/aalmiray/.gradle/caches/modules-2/files-2.1/org.openjfx/javafx-graphics/11/af47a6d3668d3ce1c61e1fe13c44471b6f8d469/javafx-graphics-11-mac.jar:/Users/aalmiray/.gradle/caches/modules-2/files-2.1/org.openjfx/javafx-graphics/11/a736dd079047ec0b72b8c4970842a5c5e0c19f2f/javafx-graphics-11.jar:/Users/aalmiray/.gradle/caches/modules-2/files-2.1/org.openjfx/javafx-base/11/4b060dad0affd866df9d959e064faa8a1a2f4af0/javafx-base-11-mac.jar:/Users/aalmiray/.gradle/caches/modules-2/files-2.1/org.openjfx/javafx-base/11/9fcd3e8e3227ec97bf503f7991fad1f3b14d005/javafx-base-11.jar:/Users/aalmiray/.gradle/caches/modules-2/files-2.1/org.kordamp.jipsy/jipsy/0.5.0/ef8711b1a8c36402d7414e83bd3c1826fb05442d/jipsy-0.5.0.jar:/Users/aalmiray/dev/github/ikonli/subprojects/ikonli-core/build/libs/ikonli-core-11.0.0-SNAPSHOT.jar --module org.kordamp.ikonli.sampler.javafx/org.kordamp.ikonli.sampler.javafx.Sampler -Dfile.encoding=UTF-8 -Duser.country=CH -Duser.language=en -Duser.variant org.kordamp.ikonli.sampler.javafx/org.kordamp.ikonli.sampler.javafx.Sampler

Notice that the --module-path flag has these two entries at the beginning

/Users/aalmiray/dev/github/ikonli/subprojects/sampler-javafx/build/classes/java/main:/Users/aalmiray/dev/github/ikonli/subprojects/sampler-javafx/build/resources/main
0 Likes

(Christian Stein) #4

Hm, you can’t have two different module-path elements with the same “tree structure”. Split package alert!

Guess, you (or the application plugin) has to use --patch-module for the resources root.

0 Likes

(Andres Almiray) #5

That’s what I thought. I also added a --patch-module instruction but it didn’t work either.

Coincidentally, what would be the new source tree conventions for dealing with this situation? (classes and resources under the same package) I woldn’t like to patch every single module just to gain access to a resource file.

0 Likes

(Andres Almiray) #6

To further clarify, the Gradle Java9 guide provides the following snippet for running the application

run {
    inputs.property('moduleName', moduleName)
    doFirst {
        jvmArgs = [
            '--module-path', classpath.asPath,
            '--module', mainClassName,
        ]
        classpath = files()
    }
}

There is no usage of resources files in the guide, only classes. As you can see, the module-path already includes both classes and resources, so the snippet is already wrong. Adding a --patch-module instruction doesn’t help either

run {
    inputs.property('moduleName', moduleName)
    doFirst {
        jvmArgs = [
            '--module-path', classpath.asPath,
            '--module', mainClassName,
            '--patch-module', "$moduleName=" + files(sourceSets.main.resources).asPath,
        ]
        classpath = files()
    }
}
0 Likes

(Christian Stein) #7

After packaging your application as modular jar, it all should work. Maybe you may instruct Gradle to run your application after it is packaged.

Adding a --patch-module instruction doesn’t help either

Mh, strange. Perhaps consulting the Javadoc helps?

https://docs.oracle.com/javase/10/docs/api/java/lang/Class.html#getResource(java.lang.String)

https://docs.oracle.com/javase/10/docs/api/java/lang/Module.html#getResourceAsStream(java.lang.String)

0 Likes

(Andres Almiray) #8

Even tried grabbing hold of the Module and querying its classloader. Doesn’t work either.

Packaging and running the application as a modular JAR is already too late. I could run the application with Gradle using pre Java9. I can run the application from the build using Maven without any extra configuration nor requiring an extra step to pack and run as an external Java process .

The problem as you said is likely related to split packages but I get no problem report when running java9c from the gradle-java9-collision plugin. Granted, the plugin might be missing something, still it has been pretty accurate so far.

0 Likes

(Andres Almiray) #9

Further information:

  • gradlew :sampler-javafx:distZip
  • cd subprojects/sampler-javafx/build/distributions/
  • unzip sampler-javafx-11.0.0-SNAPSHOT.zip
  • cd sampler-javafx-11.0.0-SNAPSHOT/lib/
  • java -p . -m org.kordamp.ikonli.sampler.javafx/org.kordamp.ikonli.sampler.javafx.Sampler

Results in the application showing the expected result. Thus the problem lies when running the application from within Gradle. How can this be fixed to make it work? Thanks :slight_smile:

2 Likes

(Abhinay Agarwal) #10

I am facing a similar issue. As @Andres_Almiray said, it runs fine from the terminal with the java command while it fails with the Gradle application plugin.

0 Likes

(Andres Almiray) #11

Related to Gradle doesn't add modules to module-path during compile

0 Likes

(Andres Almiray) #12

bump

Any news on this particular issue?

0 Likes

(StevenHachel) #13

Hey,

unfortunately, I have the same problem. It only occurs when I start it via the IDE (IntelliJ). But if I build a .jar file from it, the resources will be found. Very strange!
The message resources are not found either.

java.lang.IllegalStateException: Location is not set.
	at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2459) ~[javafx-fxml-11-win.jar:?]
	at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2435) ~[javafx-fxml-11-win.jar:?]

I have my application powered up in a spring-boot context. Maven spring: run and java -jar spring-boot-jfx.jar run smoothly.

0 Likes

(Andres Almiray) #14

A fix is now in place if you use the gradle-modularity-plugin by Paul Bakker and Sander Mak. See https://github.com/java9-modularity/gradle-modules-plugin/issues/26

1 Like

(David Hamill) #15

Thanks for sharing! I am very new to gradle and I’m having trouble applying the plugin. I was hoping I could just add the following to build.gradle:

buildscript {
  repositories {
    maven {
      url "https://plugins.gradle.org/m2/"
    }
  }
  dependencies {
    classpath "org.javamodularity:moduleplugin:1.1.1"
  }
}
apply plugin: 'org.javamodularity.moduleplugin'

But It returns the following error:

Error occurred during initialization of boot layer
java.lang.ExceptionInInitializerError
Caused by: java.lang.RuntimeException: Unable to parse --patch-module <module>=<value>: =C:\Users\David\Documents\current_work\gradle_testing\load_fxml\build\resources\main

Could you help me understand how to apply the plugin to say, the openjfx example?
https://openjfx.io/openjfx-docs/#gradle

0 Likes

(Andres Almiray) #16

You must define a module-info.java file and move the HelloFx class to a package instead of using the default package. Sadly the Gradle sample provided by Gluon is of low quality as it assumes a very basic setup.

Here’s one way to do it

https://github.com/aalmiray/hellofx
1 Like

(David Hamill) #17

thank you so much! it’s working great (now I’m trying to figure out how to get gradle to load my css files at the same time…)

0 Likes