javafxjlink

jlink showing error while comparing hashes


I am currently trying to bundle a javaFx test application via maven and jlink into a runtime image. I am using bellsoft liberica 18.0.1 as a jdk and I am running on a IntelliJ IDE. I have used the IDE to setup the project initially (via the wizard). If I hit javafx:run, everything fires up correctly, the application is displayed and all is fine.

However, running javafx:jlink produces the following error:

Error: Hash of javafx.base (d775513043c11c457939b41e544cc7a83a4076454da4a0798bdc6922ec7d3f8f) differs to expected hash (eb1d4f72b292e9bf33005b36c4afeda11b66a8745b868bf0593d1cd4c2974681) recorded in java.base java.lang.module.FindException: Hash of javafx.base (d775513043c11c457939b41e544cc7a83a4076454da4a0798bdc6922ec7d3f8f) differs to expected hash (eb1d4f72b292e9bf33005b36c4afeda11b66a8745b868bf0593d1cd4c2974681) recorded in java.base

This appears odd, as I am unsure which hashes are compared at that point. I have tried executing jlink with --fail-never as well as --lax-checksums and ignoreSigningInformation, but nothing appears to help. I have also tried to check the sha-checksums from within my m2-Repository, but I can't nail it down that way either.

Any help to sort this out is much appreciated.

EDIT: Including the current pom.xml:

<?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>com.test</groupId>
<artifactId>myapp</artifactId>
<version>1.0-SNAPSHOT</version>
<name>myappMavenModulebased</name>

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <junit.version>5.9.1</junit.version>
</properties>

<dependencies>
    <!-- https://mvnrepository.com/artifact/org.openjfx/javafx-base -->
    <dependency>
        <groupId>org.openjfx</groupId>
        <artifactId>javafx-base</artifactId>
        <version>19</version>
    </dependency>
    <dependency>
        <groupId>org.openjfx</groupId>
        <artifactId>javafx-controls</artifactId>
        <version>19</version>
    </dependency>
    <dependency>
        <groupId>org.openjfx</groupId>
        <artifactId>javafx-fxml</artifactId>
        <version>19</version>
    </dependency>
    <dependency>
        <groupId>org.openjfx</groupId>
        <artifactId>javafx-web</artifactId>
        <version>19</version>
    </dependency>
    <dependency>
        <groupId>org.controlsfx</groupId>
        <artifactId>controlsfx</artifactId>
        <version>11.1.2</version>
    </dependency>
    <dependency>
        <groupId>com.dlsc.formsfx</groupId>
        <artifactId>formsfx-core</artifactId>
        <version>11.5.0</version>
        <exclusions>
            <exclusion>
                <groupId>org.openjfx</groupId>
                <artifactId>*</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>net.synedra</groupId>
        <artifactId>validatorfx</artifactId>
        <version>0.3.1</version>
        <exclusions>
            <exclusion>
                <groupId>org.openjfx</groupId>
                <artifactId>*</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>org.kordamp.ikonli</groupId>
        <artifactId>ikonli-javafx</artifactId>
        <version>12.3.1</version>
    </dependency>
    <dependency>
        <groupId>org.kordamp.bootstrapfx</groupId>
        <artifactId>bootstrapfx-core</artifactId>
        <version>0.4.0</version>
    </dependency>
    <dependency>
        <groupId>eu.hansolo</groupId>
        <artifactId>medusa</artifactId>
        <version>16.0.1</version>
        <exclusions>
            <exclusion>
                <groupId>org.openjfx</groupId>
                <artifactId>*</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-api</artifactId>
        <version>${junit.version}</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-engine</artifactId>
        <version>${junit.version}</version>
        <scope>test</scope>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <!-- Build an executable JAR -->
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>3.1.0</version>
            <configuration>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                        <classpathPrefix>lib/</classpathPrefix>
                        <mainClass>com.test.myapp.AppLauncher</mainClass>
                    </manifest>
                </archive>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.10.1</version>
            <configuration>
                <source>18</source>
                <target>18</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>com.test.myapp/com.test.myapp.HelloApplication</mainClass>
                        <launcher>app</launcher>
                        <jlinkZipName>app</jlinkZipName>
                        <jlinkImageName>app</jlinkImageName>
                        <noManPages>true</noManPages>
                        <stripDebug>true</stripDebug>
                        <noHeaderFiles>true</noHeaderFiles>
                        <failNever>true</failNever>
                        <ignoreSigningInformation>true</ignoreSigningInformation>
                      <jlinkExecutable>/home/user/.jdks/bellsoft-jdk19.0.1/bin/jlink</jlinkExecutable>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

EDIT 2: I am providing the jlink-Tool in the pom.xml. My idea was that doing it this way, jlink would be able to create the runtime image based on the liberica-jdk. Is the problem that I am using openjfx-dependencies with the liberica-jlink-Tool?


Solution

  • What the problem is

    The module hash mismatch when using jlink occurs because:

    1. You use Liberica "Full JDK" which includes pre-built JavaFX modules in a jmod format AND
    2. You also define JavaFX dependencies in your Maven project based on JavaFX modules in jar format.

    This confuses the linker, resulting in the mismatched hash error.

    How to fix this

    You can fix this by either:

    1. Use a JDK distribution that does not include pre-built JavaFX modules (e.g. a standard OpenJDK download or a Liberica "Standard JDK" version) OR
    2. Remove the JavaFX dependencies from your pom.xml file.

    Getting some link debug info

    To debug, in the pom.xml file configuration for the javafx-maven-plugin, add:

    <jlinkVerbose>true</jlinkVerbose>
    

    This will tell you where jlink sourced the modules from (when jlink works).

    You can also run maven in debug mode (--debug command line switch for mvn). Maven will tell you a lot more information. For example, the actual full command line and option set used to invoke jlink.

    Here is a debug line for linking using OpenJDK using maven jar dependencies for the JavaFX modules:

    [DEBUG] Executing command line: [/Users/myusername/Library/Java/JavaVirtualMachines/openjdk-19.0.1/Contents/Home/bin/jlink, --module-path, /Users/myusername/dev/linktest/target/classes:/Users/myusername/.m2/repository/org/openjfx/javafx-base/19/javafx-base-19-mac.jar:/Users/myusername/.m2/repository/org/openjfx/javafx-controls/19/javafx-controls-19-mac.jar:/Users/myusername/.m2/repository/org/openjfx/javafx-fxml/19/javafx-fxml-19-mac.jar:/Users/myusername/.m2/repository/org/openjfx/javafx-graphics/19/javafx-graphics-19-mac.jar, --add-modules, com.example.linktest, --output, /Users/myusername/dev/linktest/target/app, --strip-debug, --compress, 0, --no-header-files, --no-man-pages, --verbose, --launcher, app=com.example.linktest/com.example.linktest.HelloApplication]
    

    The command line text can be useful because you can copy it and link from the command line prompt rather than from within Maven (just for testing and verification purposes).

    Linking using liberica "Full JDK" which includes JavaFX jmods

    For your pom.xml with these changes:

    And a minimal module-info.java to generate a basic JavaFX FXML application added. The linker will output:

    [INFO] --- javafx-maven-plugin:0.0.8:jlink (default-cli) @ myapp ---
    com.example.linktest file:///Users/myusername/dev/linktest/target/classes/
    java.base file:///Users/myusername/Library/Java/JavaVirtualMachines/liberica-19.0.1/jmods/java.base.jmod
    java.datatransfer file:///Users/myusername/Library/Java/JavaVirtualMachines/liberica-19.0.1/jmods/java.datatransfer.jmod
    java.desktop file:///Users/myusername/Library/Java/JavaVirtualMachines/liberica-19.0.1/jmods/java.desktop.jmod
    java.prefs file:///Users/myusername/Library/Java/JavaVirtualMachines/liberica-19.0.1/jmods/java.prefs.jmod
    java.scripting file:///Users/myusername/Library/Java/JavaVirtualMachines/liberica-19.0.1/jmods/java.scripting.jmod
    java.xml file:///Users/myusername/Library/Java/JavaVirtualMachines/liberica-19.0.1/jmods/java.xml.jmod
    javafx.base file:///Users/myusername/Library/Java/JavaVirtualMachines/liberica-19.0.1/jmods/javafx.base.jmod
    javafx.controls file:///Users/myusername/Library/Java/JavaVirtualMachines/liberica-19.0.1/jmods/javafx.controls.jmod
    javafx.fxml file:///Users/myusername/Library/Java/JavaVirtualMachines/liberica-19.0.1/jmods/javafx.fxml.jmod
    javafx.graphics file:///Users/myusername/Library/Java/JavaVirtualMachines/liberica-19.0.1/jmods/javafx.graphics.jmod
    jdk.unsupported file:///Users/myusername/Library/Java/JavaVirtualMachines/liberica-19.0.1/jmods/jdk.unsupported.jmod
    

    All of the JavaFX dependencies are sourced from the liberica provided jmods, such as this:

    liberica-19.0.1/jmods/javafx.base.jmod
    

    Linking using OpenJDK and JavaFX maven jars

    If instead you use a standard OpenJDK without pre-built JavaFX modules and JavaFX modules added as dependencies in the pom.xml, then the output is:

    [INFO] --- javafx-maven-plugin:0.0.8:jlink (default-cli) @ myapp ---
    com.example.linktest file:///Users/myusername/dev/linktest/target/classes/
    java.base file:///Users/myusername/Library/Java/JavaVirtualMachines/openjdk-19.0.1/Contents/Home/jmods/java.base.jmod
    java.datatransfer file:///Users/myusername/Library/Java/JavaVirtualMachines/openjdk-19.0.1/Contents/Home/jmods/java.datatransfer.jmod
    java.desktop file:///Users/myusername/Library/Java/JavaVirtualMachines/openjdk-19.0.1/Contents/Home/jmods/java.desktop.jmod
    java.prefs file:///Users/myusername/Library/Java/JavaVirtualMachines/openjdk-19.0.1/Contents/Home/jmods/java.prefs.jmod
    java.scripting file:///Users/myusername/Library/Java/JavaVirtualMachines/openjdk-19.0.1/Contents/Home/jmods/java.scripting.jmod
    java.xml file:///Users/myusername/Library/Java/JavaVirtualMachines/openjdk-19.0.1/Contents/Home/jmods/java.xml.jmod
    javafx.base file:///Users/myusername/.m2/repository/org/openjfx/javafx-base/19/javafx-base-19-mac.jar
    javafx.controls file:///Users/myusername/.m2/repository/org/openjfx/javafx-controls/19/javafx-controls-19-mac.jar
    javafx.fxml file:///Users/myusername/.m2/repository/org/openjfx/javafx-fxml/19/javafx-fxml-19-mac.jar
    javafx.graphics file:///Users/myusername/.m2/repository/org/openjfx/javafx-graphics/19/javafx-graphics-19-mac.jar
    jdk.unsupported file:///Users/myusername/Library/Java/JavaVirtualMachines/openjdk-19.0.1/Contents/Home/jmods/jdk.unsupported.jmod
    

    The javafx modules are sourced as jars out of the .m2 repository rather than coming as mods from the JDK:

    .m2/repository/org/openjfx/javafx-base/19/javafx-base-19-mac.jar
    

    Either way, you end up with a packaged, linked, usable JavaFX application.