Question
What should I do to be able to load resources in my JavaFX application when the application has been packaged as a Jar file?
Background
The application is a Maven project in IntelliJ IDEA. Running the application directly from IntelliJ works fine for all cases described below, but the jar file I build from the project mostly fails to load resources (images and a font).
Project Directory Tree
application
├── .idea
├── out
├── src
| ├── main
| | ├── java
| | | ├── META-INF
| | | └── Main.java
| | └── resources
| | ├── images
| | | ├── img1.jpg
| | | └── img2.png
| | ├── fonts
| | | └── font.ttf
| | └── stylesheet.css
| └── test
├── target
├── application.iml
└── pom.xml
Loading Images works like this:
Image img1 = new Image(this.getClass().getResource("images/img1.jpg").toString());
Image img2 = new Image(this.getClass().getResource("images/img2.png"));
But since I actually want to load all images in the images folder without hard-coding their names I have been doing this:
File dir = new File(this.getClass().getResource("images").getFile());
List<File> imageFiles = new ArrayList<>(Arrays.asList(dir.listFiles()));
List<Image> images = new ArrayList<>();
for (int i = 0; i < imageFiles.size(); i++) {
images.add(new Image("images/" + imageFiles.get(i).getName()));
}
This does not work when the application has been packaged into a jar file and results in a NullPointerException at line 2. It turns out that dir.listFiles()
returns null and that dir.exists()
returns false.
Loading a Font I have tried to do in two ways. Like this in stylesheet.css
:
@font-face {
font-family: 'Font';
src: url('fonts/font.ttf');
}
Or like this as the first line in the start method of Main:
Font.loadFont(getClass().getResourceAsStream("fonts/font.ttf"), 20);
In either case I am applying the font through the stylesheet. Both cases work when running the application from within IntelliJ, but neither works when running the jar. The first method prints the error message
Jun 14, 2018 4:21:47 AM com.sun.javafx.css.StyleManager loadStylesheetUnPrivileged
INFO: Could not load @font-face font [jar:file:/D:/path/in/file/system/java/application/out/artifacts/application_jar/application.jar!/fonts/font.ttf]
and the second method fails silently.
What I Have Done and Additional Information
I am building the jar in IntelliJ via Build -> Build Artifacts...
. The resources
directory is marked in IntelliJ as Resources Root and this is my pom.xml.
The generated jar file does contain all resources that I think it should have. That is, it has the following directory tree:
application.jar
├── images
| ├── img1.jpg
| └── img2.png
├── fonts
| └── font.ttf
├── META-INF
├── Main.class
└── stylesheet.css
Resources I have consulted before making this post are Apache Maven Archiver, IntelliJ Working With Artifacts, StackOverflow NullPointerException When..., StackOverflow JavaFX and maven... and several similar questions. Many of them address the NullPointerException: Location is required
issue, which seems to happen when loading a JavaFX layout from xml, which I am not doing, nor is that the error I am getting.
Note that I have virtually no previous experience with Maven, only a basic idea of file streams, class loaders etc. and some experience with JavaFX.