1

I just finished reading "JavaFX WARNING: Unsupported JavaFX configuration: classes were loaded from 'unnamed module @...'". It's a good answer, but there's one thing I don't understand. The answer seems to be to specify a module-path, to to explicitly add modules on the command line.
I've got a standalone .JAR file which actually runs my application, albeit with the JavaFX warning. I'd like to make the warning go away, but does this mean that in addition to my .JAR file, I also need to distribute a collection of JavaFX modules to my end user's platform? That's kind of a stiff price...

EQvan
  • 385
  • 4
  • 11
  • 2
    The 30,000 feet view of this is: you either need to assume the user has the JavaFX modules on their system and can point the JDK to find them, or you have to bundle and distribute then yourself. So you’re trading off ease of use for the user versus application bundle size. The same is philosophically true for any Java application. You either have to assume the user has a Java runtime, or bundle it. The recommended approach for JavaFX is the “expensive” one. Bundle a JRE and the JavaFX modules to create a native package. Mileages may vary depending on use case. – James_D Aug 12 '23 at 02:23
  • Thank you, I appreciate your candor. It seems a shame though; I have a standalone .JAR file that actually contains all the JavaFX classes. – EQvan Aug 12 '23 at 03:12
  • 1
    As noted in my answer to the Q&A you linked, nothing currently seems to break when JavaFX is placed on the class-path (so long as the main class is not a subclass of `Application`). The only downsides are that a warning is printed, and that any bugs caused by JavaFX being loaded from the unnamed module will not be fixed, as that configuration is not supported. – Slaw Aug 12 '23 at 03:19
  • jewelsea, are you asking why somebody would want to develop in Java? Assuming that they choose to, what choices do they have in the distribution of their apps? – EQvan Aug 12 '23 at 04:07
  • 2
    I removed earlier comments. No, I wasn't asking why somebody would want to develop in Java. Other choices for distribution are discussed in the [packaging section of the JavaFX tag](https://stackoverflow.com/tags/javafx/info). – jewelsea Aug 12 '23 at 12:33

1 Answers1

2

Dependencies

Any dependency needed by your application must be on the client's machine. This is true regardless of how you get that dependency on the client's machine. In general, there are two approaches.

Require Clients to Install Dependencies

This approach is really only viable for clients you control (e.g., corporate computers). Maybe you could get away with this if you can guarantee all your clients are technically savvy, or if you provide very detailed, step-by-step instructions for making your application work.

Note all non-self-contained applications make use of this approach for at least the Java Run-Time Environment (JRE) itself, which includes things like the Java Virtual Machine (JVM) and the Java standard library. In other words, the client must install a compatible version of Java on their machine to run such applications.

Deploy Dependencies with Application

There are three general approaches for doing this.

  1. Include the third-party dependencies "next to" the application (e.g., as siblings to the executable JAR file).

  2. Include the third-party dependencies and the application all in a single JAR file. This is also known as a "fat", "uber", or "shadowed" JAR file.

  3. Deploy a self-contained application. This approach embeds (i.e., "bundles") the JRE and any dependencies in the application.

Note approaches one and two both still require the client to do some work, because they must ensure a compatible version of Java is installed on their machine. The third approach typically only requires your clients to install your application itself, and typically the application appears "native" to the client's platform (e.g., an exe file on Windows).

You appear to have chosen the second approach. However, you also say:

I've got a standalone .JAR file which actually runs my application, albeit with the JavaFX warning. I'd like to make the warning go away, but does this mean that in addition to my .JAR file, I also need to distribute a collection of JavaFX modules to my end user's platform? That's kind of a stiff price...

For each individual dependency, you should choose either approach one or approach two. So, if you ship JavaFX "next to" your application's JAR file, then you should not also have JavaFX embedded in said application JAR file as well. Thus, the "price" of both approaches is the same, at least with regards to the size of the application.

Executable JARs

Broadly, both approaches one and two fall under the "executable JAR" deployment strategy. In the past, this was the standard strategy for Java applications. And it worked because many computers came with Java pre-installed. However, in a modular world, executable JARs have a few disadvantages.

  1. The JAR File Specification only supports having one module per JAR file. Meaning if you want to create a "fat" JAR file, and you have modular dependencies, said dependencies cannot keep their "module identity".

  2. The JAR File Specification does not define a Module-Path manifest attribute, only a Class-Path one. Meaning you can't have the dependencies shipped alongside the application placed on the module-path, at least not automatically.

  3. Executable JARs are launched via the -jar option, whether that's done manually or via e.g., a "double click". That places the JAR file, and any dependencies listed by the Class-Path manifest attribute, on the class-path. Modules placed on the class-path lose their "module identity" and are instead loaded into the so-called unnamed module.

Using the --module-path and --add-modules command-line options can be used to work around the second and third disadvantages (though not the first one). Unfortunately, that means you have to launch the application "manually" from a terminal or create and ship a script (e.g., a bat file on Windows) to do the same.

In the modern day, it appears the recommended strategy for deploying Java applications is to create self-contained applications. At least when your clients are "standard users" you do not control. Not only does this make using the application easier for your end users, but it also means you are in complete control of dependency versions, including Java itself.


JavaFX Applications

As you've discovered from the warning discussed in the Q&A you linked, JavaFX does not support being loaded from the unnamed module (i.e., it doesn't support being placed on the class-path). This unfortunately means that a "fat" executable JAR is not really a supported deployment strategy for JavaFX applications. But you can make it work.

  • You can force clients to have a distribution of Java that includes JavaFX installed on their machines. Two such distributions that I know of are BellSoft Liberica ("Full JRE") and Azul Zulu ("JRE FX"). Note you want your clients to have a JRE, not a JDK (which is a JRE with development tools included). Also note it's possible to create custom run-time images with jlink. You would not embed or otherwise include JavaFX with your application in this case.

  • You can ship JavaFX alongside your application JAR (instead of embedded inside the JAR). Then force your clients to launch the JAR file manually on the terminal (to specify the --module-path and --add-modules options) or, preferably, include a script to do the same.

  • You can ignore the JavaFX warning. As I noted in my answer to the Q&A you linked, nothing currently seems to break when JavaFX is placed on the class-path (other than the main class can no longer be a subclass of Application). The only downsides I'm aware of are the warning itself, and the fact that any bugs that do happen to arise from this configuration will not be fixed (since the configuration is not supported).

  • You can create your own ModuleFinder, ModuleReference, and ModuleReader implementations (and possibly a custom ClassLoader implemenation as well) that would allow embedding multiple modules in a single JAR file (by creating a custom ModuleLayer). From some basic tests I did on my own, I personally wouldn't say creating those implementations is hard, but it's certainly not trivial. The harder part is packaging the JAR file in such a way as to make this viable.

If you're going to ship your application as a standalone JAR file, then I personally would recommend simply ignoring the warning. Especially since the warning is only emitted to the console (or log files if you configure that) and so your clients should never see the warning (given JavaFX is a GUI framework).

All that said, I would also recommend you consider creating a self-contained application. This can be accomplished via jlink / jpackage (see the user guide for the latter). There's also GraalVM Native Image (also see Gluon Documentation and BellSoft's Turning JavaFX apps into native images).

Note with jlink / jpackage, you can have JavaFX in the custom run-time image, and thus loaded as named modules, regardless of your application being modular. I have little experience with GraalVM or similar technologies, but I assume something similar is possible.

Slaw
  • 37,820
  • 8
  • 53
  • 80