Issue
I have an exe file in a JavaFX project that I launch on a button click. Works fine in IDE, but if you build in jar it stops working and throws this error - java.lang.IllegalArgumentException: The file: src\main\resources\com\application\exeServices\SetProcessWorkingSetSize.exe doesn't exist.
The code I call exe
private void useCleaningService() {
final String path = "src/main/resources/com/application/exeServices/SetProcessWorkingSetSize.exe";
File file = new File(path);
try {
Desktop.getDesktop().open(file);
} catch (Exception e){
System.out.println(e);
}
}
Solution
Preface: This answer assumes you're using the "standard directory layout" of Maven/Gradle, based on the presence of src/main/java
and src/main/resources
.
Files under src/main/resources
are resources, not files. This means you have to access them using the resource-lookup API. For example:
URL url = getClass().getResource("/com/application/exeServices/SetProcessWorkingSetSize.exe");
This will give you a URL pointing to your resource, and it will do this in an application-location-independent way. In other words, it finds the resource on the class-path/module-path. If you want to read the resource then you'd open an InputStream
using URL#openStream()
(or get an InputStream
directly by using Class#getResourceAsStream(String)
). Note that resources are read-only. Also, notice the above does not include src/main/resources
in the path. That directory only exists in your project's development environment; it does not exist after deployment (nor does it exist in your build output).
As previously stated, resources are not files. This means you can't read them using the File
API. This is especially true once you package your application into a JAR file or custom run-time image, because File
has no idea how to read/reference the packaged resource.
But you have another problem. I strongly doubt Windows is capable of executing an executable file when it's packaged in a JAR file or custom run-time image. Just like the File
API of Java, Windows has no idea how to read packaged Java resources. You'd have to extract the resource into a regular file, and then have Windows execute that file. For example:
// uses java.nio.file.Path and java.nio.file.Files
private void useCleaningService() {
Path exe = Path.of(System.getProperty("user.home"), ".app_name", "SetProcessWorkingSetSize.exe");
try {
if (Files.notExists(exe)) {
try (InputStream in = getClass().getResourceAsStream("/com/application/exeServices/SetProcessWorkingSetSize.exe")) {
Files.createDirectories(exe.getParent());
Files.copy(in, exe);
}
}
Desktop.getDesktop().open(exe.toFile());
} catch (Exception ex) {
ex.printStackTrace();
}
}
This will extract the executable file to an application-specific directory (replace .app_name
with the whatever name you want for that directory) in the user's home directory (e.g., C:\Users\<username>
). It will only perform the extraction if the target file doesn't already exist. This will prevent unnecessary work, but as currently implemented, it will also prevent replacing the executable with new versions of it (unless you change the name of the target file). So, depending on your needs, you might want to modify the code to extract the resource once per application instance (can be accomplished with a simple boolean
flag).
Answered By - Slaw
Answer Checked By - Katrina (JavaFixing Volunteer)