JPackage installed Java program directory structure

Viewed 200

So I've just gotten jpackage working with a basic test program. I've ran into a problem that will essentially decide if this system will be something I can apply in real projects.

To set this up, the Java program is structured like this:

        rootDirectory
        -src folder
        -res folder

The program runs from this root directory. Files that I need for the program during runtime is in the res folder. So, the program will do something like File f = new File("res/file_i_need.png");.

I export this as a JAR, and now I'm packaging it with jpackage. The installer is made and I install the program. The resulting folder structure is like this:

    rootDirectory
        -app folder
            -res folder
            -program.jar
        -runtime folder
        -program.exe

So when you run the program, suddenly File f = new File("res/file_i_need.png"); doesn't work anymore, because the new rootDirectory has buried the res folder in the app folder.

Is there any way to configure jpackage to put the res folder in the root directory, or set it to where the app folder is used as the root directory, or is this something that you're just stuck with?

And to clarify, the following will not work for this particular usecase:

  • Storing resources in the JAR itself
  • Storing resources in other JARs

The entire point is that the user can easily edit/tweak the files in the res folder themselves.

If jpackage can't handle a scenario like this, alternatives are welcome.

Thanks for your time!

2 Answers

Perhaps the simplest solution is just to check both locations:

class ResourceLoader {
    private Path resourceDirectory = null;

    File findResourceFile(String resourceName) {
      if (resourceDirectory == null) {
          if (Path.of("app-folder/res").toFile().isDirectory()) {
              resourceDirectory = Path.of("app-folder/res");
          } else {
              resourceDirectory = Path.of("res");
      }
      return resourceDirectory.resolve(resourceName).toFile();
   }
}

You can determine where the resource directory will be without checking the existance of that FS path by using the System.getProperty("jpackage.app-path") to determine if using jpackage, then find "app" dir from the current runtime as the "app" and "runtime" folders are at the same level for Windows, MacOS and Linux.

File resourceFile(String resName) {
    String exe = System.getProperty("jpackage.app-path");
    if (exe != null) {
        return Path.of(System.getProperty("java.home"))
                    .resolveSibling("app")
                    .resolve("res").resolve(resName).toFile();
    }
    return Path.of("res", resName).toFile();
}
...
String file = resourceFile("file_i_need.png");

See jpackage documentation.

Edit

You can also set your own system property automatically using jpackage own APPDIR variable.

public static File resourceFile(String resName) {
    String appDir = System.getProperty("myAPPDIR");
    return ((appDir == null) ? Path.of("") : Path.of(appDir))
              .resolve("res").resolve(resName).toFile();
}

To do this you need to use a properties file command jpackage @jpackage.args and ensure file "jpackage.args" contains the line:

--java-options "-DmyAPPDIR=$APPDIR"
Related