1

At least a couple of vendors provide editions of their JDK/JRE products that bundle the OpenJFX implementation of JavaFX technology. Namely, Azul Systems and BellSoft.

If deploying a JavaFX app to users’ machines where a JVM bundled with JavaFX technology has already been installed, how do I write the dependencies and executions portions of the Maven POM driving my build?

Dependencies

Do I want to not bundle any OpenJFX libraries with my app, if I know a JVM bundled with OpenJFX is present?

If so, how do I write the POM to make the OpenJFX libraries available to me while developing but not include them in my final JAR file?

Currently I have this given to me by the JavaFX project template provided by IntelliJ:

<dependencies>

    <dependency>
        <groupId>org.openjfx</groupId>
        <artifactId>javafx-controls</artifactId>
        <version>20.0.2</version>
    </dependency>

    <dependency>
        <groupId>org.openjfx</groupId>
        <artifactId>javafx-fxml</artifactId>
        <version>20.0.2</version>
    </dependency>

    <dependency>
        <groupId>org.controlsfx</groupId>
        <artifactId>controlsfx</artifactId>
        <version>11.1.2</version>
    </dependency>
…

Executions of javafx-maven-plugin

How do I configure the executions element of my javafx-maven-plugin element in the POM if I want to build just a JAR without any bundling of a JVM or native image?

Right now I have the following, given by the JavaFX project template provided by IntelliJ:

<plugin>
    <groupId>org.openjfx</groupId>
    <artifactId>javafx-maven-plugin</artifactId>
    <version>0.0.8</version>
    <executions>
        <execution>
            <!-- Default configuration for running with: mvn clean javafx:run -->
            <id>default-cli</id>
            <configuration>
                <mainClass>work.basil.voters.voters_wa/work.basil.voters.voters_wa.HelloApplication</mainClass>
                <launcher>app</launcher>
                <jlinkZipName>app</jlinkZipName>
                <jlinkImageName>app</jlinkImageName>
                <noManPages>true</noManPages>
                <stripDebug>true</stripDebug>
                <noHeaderFiles>true</noHeaderFiles>
            </configuration>
        </execution>
    </executions>
</plugin>

Below is the entire POM.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>work.basil.voters</groupId>
    <artifactId>voters_wa</artifactId>
    <version>1.0-SNAPSHOT</version>
    <name>Voters WA</name>
    <description>Parses Washington State voter registration data, then providing access via queries and reporting. For political purposes only. Commercial use of that data is prohibited by law.</description>
    <inceptionYear>2023</inceptionYear>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.plugin.validation>VERBOSE</maven.plugin.validation>
    </properties>

<dependencies>

    <dependency>
        <groupId>org.openjfx</groupId>
        <artifactId>javafx-controls</artifactId>
        <version>20.0.2</version>
    </dependency>

    <dependency>
        <groupId>org.openjfx</groupId>
        <artifactId>javafx-fxml</artifactId>
        <version>20.0.2</version>
    </dependency>

    <dependency>
        <groupId>org.controlsfx</groupId>
        <artifactId>controlsfx</artifactId>
        <version>11.1.2</version>
    </dependency>

        <!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter -->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>5.10.0</version>
            <scope>test</scope>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.11.0</version>
                <configuration>
                    <source>20</source>
                    <target>20</target>
                </configuration>
            </plugin>
<plugin>
    <groupId>org.openjfx</groupId>
    <artifactId>javafx-maven-plugin</artifactId>
    <version>0.0.8</version>
    <executions>
        <execution>
            <!-- Default configuration for running with: mvn clean javafx:run -->
            <id>default-cli</id>
            <configuration>
                <mainClass>work.basil.voters.voters_wa/work.basil.voters.voters_wa.HelloApplication</mainClass>
                <launcher>app</launcher>
                <jlinkZipName>app</jlinkZipName>
                <jlinkImageName>app</jlinkImageName>
                <noManPages>true</noManPages>
                <stripDebug>true</stripDebug>
                <noHeaderFiles>true</noHeaderFiles>
            </configuration>
        </execution>
    </executions>
</plugin>
        </plugins>
    </build>
</project>
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
  • "_Do I want to not bundle any OpenJFX libraries with my app, if I know a JVM bundled with OpenJFX is present?_" – Correct. If JavaFX is going to be provided by the client's installation of Java, then you should not include JavaFX in your application. "_If so, how do I write the POM to make the OpenJFX libraries available to me while developing but not include them in my final JAR file?_" – Does using `provided` work? – Slaw Jul 30 '23 at 07:28

1 Answers1

2

A short guide to using Maven to work with JDKs and runtimes that already include JavaFX:

  • Azul Zulu "JDK FX" and "JRE FX".
  • BellSoft Liberica "Full JDK" or "Full JRE".

Development

For development you have these choices:

  1. Include the JavaFX maven dependencies in your pom.xml and work with a JDK that does not include JavaFX.
  2. Include the JavaFX maven dependencies in your pom.xml and work with a JDK that includes JavaFX.
  3. Don't place the JavaFX maven dependencies in your pom.xml and work with a JDK that includes JavaFX.
  4. Include the JavaFX maven dependencies in your pom.xml as a provided scope and work with a JDK that includes JavaFX.
Development
scenario
JavaFX dependencies
included in POM
JDK bundled
with OpenJFX
Comment
# 1 More portable for sharing with developers
# 2
# 3
# 4
<scope>provided</scope>
• Leanest option for when all developers and all users have installed appropriate JDK/JRE with JavaFX
• Also for non-modular app in shaded JAR

Any of the options will work.

Option 1 is probably the most portable if you share the project with other developers. Then the developers won't have to be extra careful to find and use a JDK that includes JavaFX (which is rarer than ones that don't have JavaFX).

Option 4 is probably best if you know that all developers will be using an appropriate JDK that includes JavaFX or if your target is to build a non-modular shaded jar for the application. By using scope provided, your final app artifact will lack the OpenJFX libraries thereby producing a smaller size.

Distribution

For distribution, you don't need to include the JavaFX maven jars, because you know your target platform will have those.

When you build your app, by default, it will create a jar file for the application. And that jar file will not include the dependent code. This is the default execution of the maven-jar-plugin, which is implicitly included with the maven distribution, so you don't need any configuration to use it in its default mode.

Even though you don't need the JavaFX modules as dependencies, you do need any other dependencies your app requires. If it is a simple app with no other dependencies, then you don't need to worry about this. But if it is not a simple app, then you need to a way to include those dependencies.

If it is a modular app, you can create a zip of the dependent jars, your app jar and an execution script. The job of the execution script is to find the Java command and use it to run your application with the dependent modules on the module path.

This can be done using the maven-assembly plugin, which can be configured to:

  1. Copy your application jar to an assembly directory.
  2. Copy your application dependencies (excluding JavaFX dependencies) to the assembly directory.
  3. Copy the execution script to the assembly directory.
  4. Create the zip file for the distribution.

If you do include the JavaFX maven jars in the assembly, it will probably still work if it is a modular app, it is just not necessary in your case. They can be excluded either by not having them as dependencies in the project to start with, or if they are there, then in the assembly definition, filtering them out (by filtering out all dependencies from the org.openjfx group id).

If it is a non-modular application, you can use the shade plugin, to shade your application code and all of the code from the dependent libraries into a single jar file. If you use this option, then don't put dependencies on the JavaFX Maven artifacts in your project file (or use provided scope for them), because you don't want to shade the JavaFX code into your jar file, it will only create confusion when the underlying platform already makes JavaFX available. In such a case, you should do your development using a JDK which includes JavaFX.

Provided scope

If desired, the scope provided can be set for the JavaFX jars to indicate that they don't need to be bundled as runtime dependencies for the application because they are already part of the target platform, yet are still available at development and build time, so that you can compile against them.

<scope>provided</scope>

When provided scope is set, by default, tasks that function based on dependencies such as shading or assembly copying tasks, won't also copy the provided dependencies, because the tasks know they won't be needed.

The use of provided scope for JavaFX dependencies in this case for targeting runtimes which already include JavaFX is similar to the use of provided scope on servlet API dependencies in web development when targeting a web application server that includes the Java servlet API.

FAQ

How do I configure the executions element of my javafx-maven-plugin element in the POM if I want to build just a JAR without any bundling of a JVM or native image?

You don't. If you aren't building a native image using jlink via the javafx-maven-plugin, then there is no need to use it, you can delete it from the project.

Aside from the linking function, the javafx-maven-plugin also has the ability to launch a JavaFX application. I don't use that, and rely on my IDE execution ability to run my application. But if you were in the habit of using the javax:run target of the javafx-maven-plugin, you could keep the plugin around for that.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
jewelsea
  • 150,031
  • 14
  • 366
  • 406
  • Would use of `provided` be a legitimate Option # 4 on your list of development scenarios? – Basil Bourque Jul 30 '23 at 15:04
  • @BasilBourque yes, I updated the answer to reflect that. – jewelsea Jul 30 '23 at 18:53
  • Please verify (a) my edits to the text of your development scenario # 4, and (b) the correctness of the summary table of development scenarios I added to your helpful Answer. (I had really botched up my edits, but I think I got it straight now.) – Basil Bourque Jul 30 '23 at 22:25
  • @BasilBourque changes look good, thx for adding the table, it's clearer. – jewelsea Jul 31 '23 at 03:11