Maven Shade Javafx Runtime Components Are Missing

Maven Shade JavaFX runtime components are missing

UPDATE 10/2021

Since JavaFX 16 a warning is displayed when JavaFX doesn't run on the module path, which is the case of an uber/fat jar:

$ java -jar myFatJar-1.0-SNAPSHOT.jar
Oct 02, 2021 1:45:21 PM com.sun.javafx.application.PlatformImpl startup
WARNING: Unsupported JavaFX configuration: classes were loaded from 'unnamed module @14c24f4c'

Also, you get a warning from the shade plugin itself:

[WARNING] Discovered module-info.class. Shading will break its strong encapsulation.

While these warnings can be initially ignored, there is a reason for them.

As explained in this CSR:

JavaFX is built and distributed as a set of named modules, each in its own modular jar file, and the JavaFX runtime expects its classes to be loaded from a set of named javafx.* modules, and does not support loading those modules from the classpath.

And:

when the JavaFX classes are loaded from the classpath, it breaks encapsulation, since we no longer get the benefit of the java module system.

Therefore, even this widely accepted answer explains how can an uber/fat jar can be created on Maven projects, its use is discouraged, and other modern alternatives to distribute your application, like jlink, jpackage or native-image, should be used.

ORIGINAL ANSWER

This answer explains why a fat/uber jar fails on JavaFX 11. In short:

This error comes from sun.launcher.LauncherHelper in the java.base module. The reason for this is that the Main app extends Application and has a main method. If that is the case, the LauncherHelper will check for the javafx.graphics module to be present as a named module. If that module is not present, the launch is aborted.

And already proposes a fix for Gradle.

For Maven the solution is exactly the same: provide a new main class that doesn't extend from Application.

You will have new class in your application package (bad name):

// NewMain.java
public class NewMain {

public static void main(String[] args) {
Main.main(args);
}
}

And your existing Main class, as is:

//Main.java
public class Main extends Application {

@Override
public void start(Stage stage) {
...
}

public static void main(String[] args) {
launch(args);
}
}

Now you need to modify your pom and set your main class for the different plugins:

<mainClass>application.NewMain</mainClass>

Platform-specific Fat jar

Finally, with the shade plugin you are going to produce a fat jar, on your machine.

This means that, so far, your JavaFX dependencies are using a unique classifier. If for instance you are on Windows, Maven will be using internally the win classifier. This has the effect of including only the native libraries for Windows.

So you are using:

  • org.openjfx:javafx-controls:11
  • org.openjfx:javafx-controls:11:win
  • org.openjfx:javafx-graphics:11
  • org.openjfx:javafx-graphics:11:win <-- this contains the native dlls for Windows
  • org.openjfx:javafx-base:11
  • org.openjfx:javafx-base:11:win

Now, if you produce the fat jar, you will bundle all those dependencies (and those other regular third party dependencies from your project), and you will be able to run your project as:

java -jar myFatJar-1.0-SNAPSHOT.jar

While this is very nice, if you want to distribute you jar, be aware that this jar is not cross-platform, and it will work only on your platform, in this case Windows.

Cross-Platform Fat Jar

There is a solution to generate a cross-platform jar that you can distribute: include the rest of the native libraries of the other platforms.

This can be easily done, as you just need to include the graphics module dependencies for the three platforms:

<dependencies>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>11</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-graphics </artifactId>
<version>11</version>
<classifier>win</classifier>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-graphics </artifactId>
<version>11</version>
<classifier>linux</classifier>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-graphics </artifactId>
<version>11</version>
<classifier>mac</classifier>
</dependency>
</dependencies>

Size

There is a main issue with this approach: the size. As you can see in this other answer, if you use the WebView control, you will be bundling around 220 MB due to the WebKit native libraries.

JavaFX Maven project in IntelliJ. JavaFX runtime components are missing only in IntelliJ. JAR through mvn package executes without issues

This is more a troubleshooting and research guide than an actual fix. Fixes for environmental issues are difficult to provide in a StackOverflow context. However, if you study the information here, it might help you fix your project.

Recommended troubleshooting approach

Use the Intellij new JavaFX project wizard. Ensure that it works in your environment, then gradually add components from your current project into the working project, checking that everything still works after each small addition.

Debugging when executing via the JavaFX maven plugin

I think the above recommendation is the preferred approach, however, you can alternately get the following to work:

run with: mvn clean javafx:run
The need to execute with IntelliJ is to debug the code"

See:

  • intellij idea : how to debug a java:fx maven project?

I also think you can just right-click on the maven target for javafx:run and select Debug. I am not sure, I don't make use of the JavaFX maven plugin.

Creating fat jars for JavaFX applications

the fat jar

This is not a recommended configuration, but if you really must do it, you can review:

  • Maven Shade JavaFX runtime components are missing

That answer doesn't discuss getting such a configuration to work in conjunction with an Idea run/debug configuration, so it may not assist you.

If you do continue with a fat jar, I would not advise using a module-info, as you will be running code off the classpath anyway.

Modular versus non-modular JavaFX applications

If you don't use a fat jar, getting all the module dependencies correct for Spring is tricky anyway because Spring is not currently architected to directly support modules well. Spring 6 will be designed to work well with modules, though I think you should be able to get Spring 5 to work if you try hard enough (I have got it to work in the past for some applications).

Alternately you can just have the JavaFX components as modules and run the rest off the classpath. For example, the "Non-modular with Maven" approach at openjfx.io. Note that in that approach, the JDK and JavaFX modules are still loaded as modules off of the module path, it is only Spring your application that is not providing a module-info.java file and running off the classpath.

Creating runtime images for JavaFX applications

I also advise studying:

  • these resources for the creation of an appropriate runtime image.

Error: JavaFX runtime components are missing, (Permanent Solution)

Recommended Alternatives

See the packaging resources of the JavaFX tag for recommended alternate solutions to a jar distribution: jlink, jpackage, or native image.

Using JRE's that include JavaFX

Pre-installed JREs that include JavaFX, such as some Bellsoft, Zulu, and Corretto distributions, will execute JavaFX apps without additional module specifiers because they include the JavaFX modules in the base module setup for their distributions.

Note, you must use the correct versions of the JDKs if you want a JDK which includes JavaFX (not all JDKs include JavaFX):

  • for BellSoft, download and install the "Full JDK", not the "Standard JDK".
  • for Zulu, download and install the package type "JDK FX", not "JDK".

You can also create your own JRE distribution that includes JavaFX modules using jlink (which is actually simpler to do than it may sound).

Using ant to build a single JAR containing App and JavaFX components

But I still hope that there might be a solution for the above while working with ANT as building tool for JavaFX.

There is some info on building modular JavaFX apps with ant in this answer:

  • bad name in value for --add-modules when trying to compile through ant

It probably isn’t everything you are looking for though.

To create a single executable jar using ant, you could try emulating the output of this maven JavaFX shade on classpath answer:

  • Maven Shade JavaFX runtime components are missing

But use ant tasks to build the massive shaded jar instead of maven. I don’t have explicit instructions for that, you would need to work out to accomplish that non-trivial task yourself.

The created jar will include a launcher class, your application code, dependent library code, JavaFX java, and native code. The jar will run on any modern JRE as long as you have included the native code for the relevant platform. The jar will run in the unsupported classpath configuration.

Zip Distributions

Or (better) create a zip distribution:

  1. only put your own code in your app jar.

  2. place the dependent libraries and JavaFX modules in a lib directory.

  3. Create a script that invokes Java with your jar file running with the modules in the lib directory added.

  4. Make your app modular if possible:

    • Define a module-info.java.
    • This step isn’t strictly necessary or reasonably possible for some apps.
  5. Use ant to place everything in a zip file for distribution.

  6. Include a jlink generated JRE in the zip if you want.

Note: the maven JavaFX plugin, once properly configured, can accomplish most of these tasks with a single command:

mvn javafx:jlink

Additional info

  • See the eden guide for resolving JavaFX runtime components.

JavaFX runtime components are missing, even though I already have them in my VM options and Modules

Okay, so I found out why this is occurring.

I put the module path and add modules in the program arguments and not in the vm options, which is what is causing the red issue.

Now I am encountering a "Error occurred during initialization of boot layer" issue now.



Related Topics



Leave a reply



Submit