In Intellij IDEA, I am trying to load resources in my Maven JavaFX modular project.
Here's my project's structure :
myProject
- src
- main
- java
- com
- example
- myPackage
- myApp.java
- module-info.java
- resources
- fonts
- font.ttf
- font.ttf
I duplicated the font I am trying to load in resources
to test the following :
ClassLoader loader = Thread.currentThread().getContextClassLoader();
URL rootFile = loader.getResource("font.ttf"); // this works
URL subfolderFile = loader.getResource("fonts/font.ttf"); // this does not work
System.out.println(rootFile); // file:/C:/Users/... stuff .../myProject/target/classes/font.ttf
System.out.println(subfolderFile); // null, was expecting file:/C:/Users/... stuff .../myProject/target/classes/fonts/font.ttf
I was unable to find any posts answering my problem. Does anyone have an explanation ?
Note the documentation of ClassLoader#getResource(String)
:
Resources in named modules are subject to the encapsulation rules specified by
Module.getResourceAsStream
. Additionally, and except for the special case where the resource has a name ending with ".class", this method will only find resources in packages of named modules when the package is opened unconditionally [emphasis added] (even if the caller of this method is in the same module as the resource)
You have a module-info.java
file, so your code is in a named module. The fonts/font.ttf
resource is in the fonts
package, so it is encapsulated. Whereas the font.tff
resource is at the root of the module, meaning it is not in a package, thus it is not encapsulated.
If you add:
opens fonts;
To your module-info.java
file then you should be able to load fonts/font.ttf
via a ClassLoader
.
That said, it is often simpler to use Class#getResource(String)
. Particularly if the caller, the class, and the resource are all in the same module.