jdeps 失败,fat jar 中有 Java 11 和 JavaFX

jdeps fails with Java 11 and JavaFX in fat jar

我正在尝试使用 jdeps(和 jlink)来部署我的 Java 11 应用程序,该应用程序正在使用 JavaFX 11。在我的 [=27] 中一切正常 运行 =] IDE。但是当我使用 jdep 时出现以下错误,这表明找不到某些模块或包。我卡住了。感谢您的帮助。

jdeps --list-deps --module-path /Users/…/target:/Library/Java/JavaVirtualMachines/jdk-11.0.2.jdk/Contents/Home/jmods:/Users/…/javafx-sdk-11.0.2/lib --add-modules chaincoder,javafx.fxml,javafx.base,javafx.controls,javafx.graphics,javafx.web /Users/…/target/chaincoder4-1.0.jar

Error: Module javafx.media contains package javafx.collections, module javafx.base exports package javafx.collections to javafx.media

模块-info.java 是

模块链编码器{

requires   javafx.web;
requires   javafx.graphics;
requires   javafx.controls;
requires   javafx.fxml;
requires   javafx.base;
requires   javafx.media;

requires java.desktop;
requires java.base;
requires java.xml;
requires java.logging;

requires jdk.jsobject;

exports   core;

}

pom.xml 是

        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-graphics</artifactId>
            <version>11.0.2</version>
        </dependency>

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

        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-base</artifactId>
            <version>11.0.2</version>
        </dependency>

        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-media</artifactId>
            <version>11.0.2</version>
        </dependency>

        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-web</artifactId>
            <version>11.0.2</version>
        </dependency>

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


<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>core.Main</mainClass>
                    </manifest>
                </archive>
            </configuration>
        </plugin>

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-dependency-plugin</artifactId>
            <version>2.6</version>
            <executions>
                <execution>
                    <id>unpack-dependencies</id>
                    <phase>package</phase>
                    <goals>
                        <goal>unpack-dependencies</goal>
                    </goals>
                    <configuration>
                        <excludeScope>system</excludeScope>
                        <excludeGroupIds>junit,org.mockito,org.hamcrest</excludeGroupIds>
                        <outputDirectory>${project.build.directory}/classes</outputDirectory>
                    </configuration>
                </execution>
            </executions>
        </plugin>

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.8.0</version>
            <configuration>
                <source>11</source>
                <target>11</target>
                <compilerArguments>
                    <bootclasspath>${sun.boot.class.path}${path.separator}${java.home}/lib/jfxrt.jar</bootclasspath>
                </compilerArguments>
            </configuration>
        </plugin> 
    </plugins>

</build>

您使用 maven-dependency-plugin 插件的原因是什么?

如果你看到 unpack-dependencies 目标在做什么,你会注意到 target/classes 文件夹包含超过 90 MB 的 类,在插件提取所有项目依赖项之后,包括 JavaFX 的,并将它们全部组合起来。

猜猜每个不同的 JavaFX 模块的不同 module-info.class 文件会发生什么情况?只有一个占上风,在这种情况下,来自 javafx.media.

的那个

所以您在 target/classes!

中创建了一个新模块

它名为 javafx.media,包含您的项目 类 和 所有 JavaFX 类,并且包括来自 [=25] 的所有项目=] 或 javafx.graphics.

如果您查看此 target/classes/module-info.class 文件:

module javafx.media {
    requires transitive javafx.base;
    requires transitive javafx.graphics;
    ...
}

这个 "module",它已经包含了所有的 JavaFX 类,还需要 再次 来自 javafx.base 的那些 类和 javafx.graphics,复制它们。

这解释了您的错误消息:

Error: Module javafx.media contains package javafx.collections, 
       module javafx.base exports package javafx.collections to javafx.media

现在您可以看到您的 new 模块 javafx.media 包含许多包,这些包也从 javafx.base 导出到它,这违反了 split package not allowed 条件:

The same Java package can only be exported by a single Java module at runtime. In other words, you cannot have two (or more) modules that export the same package in use at the same time. The Java VM will complain at startup if you do.

可能的解决方案

  • 也许您根本不需要 maven-dependency-plugin 插件?如果你不需要它,请将其删除。

  • 您正在将包含所有 JavaFX 类 的 target 文件夹添加到模块路径:

    jdeps --list-deps --module-path /Users/…/target:...
    

显然这是错误的,因为 classes 文件夹包含所有 JavaFX 类 和一个错误的模块信息描述符。它不是一个有效的模块,所以只需将它从模块路径中删除。

  • 那么你不需要将 JDK 路径添加到模块路径,这是默认完成的。

所以你可以拥有:

jdeps --list-deps --module-path /Users/…/javafx-sdk-11.0.2/lib
  • 然后,当您添加模块时,您不需要添加 javafx.basejavafx.graphics,因为它们包含在传递依赖项中(这也适用于您的 pom 中列出的依赖项).例如参见 [​​=41=]。

所以你将拥有:

jdeps --list-deps --module-path /Users/…/javafx-sdk-11.0.2/lib
    -add-modules chaincoder,javafx.fxml,javafx.web
  • 但是请注意,您有一个名为 chaincoder 的模块,它已经包含了所有需要的模块,因此您可以只拥有这个:

    jdeps --list-deps --module-path /Users/…/javafx-sdk-11.0.2/lib
        -add-modules chaincoder /Users/…/target/chaincoder4-1.0.jar
    

应该可以。

最后一点,您可以从编译器插件中删除 jfxrt.jar

<configuration>
    <source>11</source>
    <target>11</target>
    <compilerArguments>
            <bootclasspath>${sun.boot.class.path}${path.separator}${java.home}/lib/jfxrt.jar</bootclasspath>
    </compilerArguments>
</configuration>

因为它已经不存在了。您已将所有 JavaFX 类 包含在依赖项中:

<configuration>
    <source>11</source>
    <target>11</target>
</configuration>