问题描述
我需要在带有 JavaFX 的 maven 项目中使用 Reflections,并且我想使用 jlink
来捆绑最小的 JRE。
问题是我在运行 mvn clean compile javafx:jlink
时出现以下错误:
[WARNING] required filename-based automodules detected. Please don't publish this project to a public artifact repository!
Error: automatic module cannot be used with jlink: reflections from file:///C:/Users/Daniel/.m2/repository/org/reflections/reflections/0.9.12/reflections-0.9.12.jar
[ERROR] Command execution Failed.
org.apache.commons.exec.ExecuteException: Process exited with an error: 1 (Exit value: 1)
at org.apache.commons.exec.DefaultExecutor.executeInternal (DefaultExecutor.java:404)
at org.apache.commons.exec.DefaultExecutor.execute (DefaultExecutor.java:166)
at org.openjfx.JavaFXBaseMojo.executeCommandLine (JavaFXBaseMojo.java:504)
at org.openjfx.JavaFXBaseMojo.executeCommandLine (JavaFXBaseMojo.java:394)
at org.openjfx.JavaFXJLinkMojo.execute (JavaFXJLinkMojo.java:187)
at org.apache.maven.plugin.DefaultBuildpluginManager.executeMojo (DefaultBuildpluginManager.java:137)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:210)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:156)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:148)
at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:117)
at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:81)
at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build (SingleThreadedBuilder.java:56)
at org.apache.maven.lifecycle.internal.LifecycleStarter.execute (LifecycleStarter.java:128)
at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:305)
at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:192)
at org.apache.maven.DefaultMaven.execute (DefaultMaven.java:105)
at org.apache.maven.cli.MavenCli.execute (MavenCli.java:957)
at org.apache.maven.cli.MavenCli.doMain (MavenCli.java:289)
at org.apache.maven.cli.MavenCli.main (MavenCli.java:193)
at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0 (Native Method)
at jdk.internal.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62)
at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke (Method.java:564)
at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced (Launcher.java:282)
at org.codehaus.plexus.classworlds.launcher.Launcher.launch (Launcher.java:225)
at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode (Launcher.java:406)
at org.codehaus.plexus.classworlds.launcher.Launcher.main (Launcher.java:347)
org.apache.commons.exec.ExecuteException: Process exited with an error: 1 (Exit value: 1)
at org.apache.commons.exec.DefaultExecutor.executeInternal(DefaultExecutor.java:404)
at org.apache.commons.exec.DefaultExecutor.execute(DefaultExecutor.java:166)
at org.openjfx.JavaFXBaseMojo.executeCommandLine(JavaFXBaseMojo.java:504)
at org.openjfx.JavaFXBaseMojo.executeCommandLine(JavaFXBaseMojo.java:394)
at org.openjfx.JavaFXJLinkMojo.execute(JavaFXJLinkMojo.java:187)
at org.apache.maven.plugin.DefaultBuildpluginManager.executeMojo(DefaultBuildpluginManager.java:137)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:210)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:156)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:148)
at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:117)
at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:81)
at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build(SingleThreadedBuilder.java:56)
at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:128)
at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:305)
at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:192)
at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:105)
at org.apache.maven.cli.MavenCli.execute(MavenCli.java:957)
at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:289)
at org.apache.maven.cli.MavenCli.main(MavenCli.java:193)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:564)
at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:282)
at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:225)
at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:406)
at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:347)
问题是反射不支持 JPMS,jlink
只需要显式模块。
我已经看到 this answer 描述了如何将外部 JAR 转换为模块,但我需要在运行 jlink
之前在我的 Maven 构建中自动执行此操作。
我也遇到了 moditect 正好允许这样做,但我没有在我的项目中完成这项工作,因为我不知道如何告诉 javafx:jlink
使用反射库的转换后的 JAR
我也可以想象使用 exec-maven-plugin
来运行 jlink 命令,但我不知道如何告诉 javafx-maven-plugin 在不修改本地存储库的情况下接受它。
如何在将自动化模块(反射)作为依赖项的同时使用 jlink
的 javafx-maven-plugin
目标?
我的 module-info.java
看起来像这样(简化):
module my.project{
exports my.project.toscan to reflections;
exports my.project.ui to javafx.graphics;
opens my.project.ui.controllers to javafx.fxml;
requires javafx.controls;
requires javafx.fxml;
requires transitive javafx.graphics;
requires javafx.base;
requires reflections;
}
这是我的 pom.xml
(也简化了):
<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>my</groupId>
<artifactId>project</artifactId>
<version>myversion</version>
<dependencies>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>14</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>14</version>
</dependency>
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.9.12</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<release>14</release>
</configuration>
</plugin>
<plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>0.0.4</version>
<configuration>
<source>14</source>
<target>14</target>
<release>14</release>
<mainClass>my.project.MainClass</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
这类似于后来询问的 this question。
解决方法
你为什么坚持要专门使用这个工具链?您可以使用 jlink 创建 JavaFX 程序,而无需先模块化所有内容。也许您可以按照我在此处与 Dirk 描述的路线进行操作:https://github.com/dlemmermann/JPackageScriptFX 好处基本相同,我没有看到在整个应用程序中使用 jlink 的任何额外好处。