Issue
I have put all my JavaFX code into a executable JAR-file. Everything is inside there.
When I compile it with Eclipse IDE, it works, but when I try to execute the JAR-file, I get an error.
Caused by: javafx.fxml.LoadException:
file:/home/asus/program/JUSBPlotter/JUSBPlotter-0.0.1-SNAPSHOT-jar-with-dependencies.jar!/se/danielmartensson/fxml/front.fxml
When I have this Java code
Parent root = FXMLLoader.load(getClass().getResource("/se/danielmartensson/fxml/front.fxml"));
There is nothing wrong with the FXML file.
fx:controller="se.danielmartensson.controller.Front"
Also I get errors when I try to display a picture in JavaFX.
Caused by: java.io.FileNotFoundException: file:/home/asus/program/JUSBPlotter/JUSBPlotter-0.0.1-SNAPSHOT-jar-with-dependencies.jar!/se/danielmartensson/pictures/computer.png (No such file or directory)
When I have this Java code:
FileInputStream picture1 = new FileInputStream(getClass().getResource("/se/danielmartensson/pictures/computer.png").getFile());
Question: How can I tell Java the correct file path in JAR-file?
Solution
One thing to remember is that resources are not the same thing as files, despite the fact they appear quite similar—especially before packaging an application. Once you package an application those resource files become entries in a JAR file which, while they can be thought of as files, cannot be accessed in the same way as files. In particular, the java.io.File
API does not understand how to read those entries. You can, however, access these entries through the URL
returned by Class#getResource(String)
or the InputStream
returned by Class#getResourceAsStream(String)
. Note the latter basically just finds the URL
and, if it exists, calls URL#openStream()
. The reason you can access JAR entries (i.e. resources) with the URL
is due to the JarURLConnection
and related classes; I won't go into detail about how URLs are handled by Java as that's out of scope for this answer.
Now, since you're trying to display an image in JavaFX I assume you're using the Image
class. There are basically three ways you can tell an Image
where the image resource is.
Use
Image#<init>(String)
where the argument URL has no scheme. In this case the class will treat the URL as a path relative to the root of the classpath and try to access the image accordingly. Basically, the argument is the same argument you'd give toClass#getResource(String)
, except that the path must be absolute (i.e. not relative to any class). This behavior is documented by theImage
class:All URLs supported by
URL
can be passed to the constructor. If the passed string is not a valid URL, but a path instead, the Image is searched on the classpath in that case.Note: If you're using modules then resource encapsulation comes into play when using this option. See GitHub Issue #441.
Use the same constructor as used above but pass a valid URL (i.e. it has a scheme). When using a resource, you can simply convert the
URL
returned byClass#getResource(Sring)
into aString
usingURL#toExternalForm()
.Image image = new Image(getClass().getResource(...).toExternalForm());
Note: You can also use
URL#toString()
which returns the same value.Use
Image#<init>(InputStream)
. Here you can useClass#getResourceAsStream(String)
. Don't forget to close theInputStream
when done with it.try (InputStream is = getClass().getResourceAsStream(...)) { Image image = new Image(is); }
All this assumes that the resources have been properly packaged in your JAR file when you built it. If that's not the case, follow the advice given by José Pereda in the question comments first.
Note that one can access the entries of a ZIP/JAR file using the java.util.zip.*
API, the java.util.jar.*
API, or the Java NIO's ZipFileSystemProvider
. Each of these, especially the last option, allow you to access the entries of a ZIP/JAR file similar to actual files because they're designed specifically to do so. However, when using resources in an application you should stick with Class#getResource(String)
and related methods.
Answered By - Slaw
Answer Checked By - Senaida (JavaFixing Volunteer)