【问题标题】:Package#getImplementationVersion() returns null with native image (GraalVM/GluonFX)Package#getImplementationVersion() 使用本机图像返回 null (GraalVM/GluonFX)
【发布时间】:2022-01-22 07:55:45
【问题描述】:

我有一个基于 JavaFX 的桌面应用程序,我通过 GraalVM/GluonFX 创建本机图像。为了在运行时检索应用程序的版本,我之前——当应用程序只有一个胖 JAR 时——使用了Package#getImplementationVersion()。但是,这会返回 null

我认为这是因为我没有正确设置清单条目?我对gluonfx-maven-plugin的配置:

<plugin>
    <groupId>com.gluonhq</groupId>
    <artifactId>gluonfx-maven-plugin</artifactId>
    <version>1.0.10</version>
    <configuration>
        <mainClass>${mainClass}</mainClass>
        <nativeImageArgs>
            <arg>--allow-incomplete-classpath</arg>
            <arg>--initialize-at-build-time=org.pdfclown.Version</arg>
            <arg>--no-fallback</arg>
        </nativeImageArgs>
    </configuration>
</plugin>

有没有办法配置插件,使Package#getImplementationVersion() 返回应用程序的版本?我在corresponding documentation 中找不到东西。此外,GraalVM 中的 related issue 已在 2020 年解决。

【问题讨论】:

  • 如果你在 JVM (mvn gluonfx:run) 上运行它可以工作吗?如果不是这样,它与 GluonFX 插件或 GraalVM 无​​关。它有效,我认为您正在使用清单文件,因此您可能需要将其作为资源包含在内。先运行mvn gluonfx:runagent,然后再次构建原生镜像。如果这不起作用,请发布重现问题的完整方法。
  • @JoséPereda 不,它不适用于 gluonfx:run 目标。我也没有清单文件。对于胖 JAR,我使用的是 shade 插件,它有一个 ManifestResourceTransformer。它允许设置,例如,实现版本为${project.version}。 GluonFX 插件是否提供类似的功能?
  • gluonfx:runjavafx:run 相同。在任何情况下,鉴于您要构建原生图像,如果您从源代码构建,则不需要 shade 插件。如果我没看错,您只想将${project.version} 传递给您的应用程序,不是吗?为什么不使用 Maven resources 插件并添加一个可以从代码中读取的属性文件?
  • @JoséPereda 是的,使用属性文件将是一种替代解决方案,我已经考虑过了。我只是好奇是否有一个“GluonFX 插件”——让Package#getImplementationVersion() 工作的方式?
  • 在回答这个问题之前,当您构建 fat jar 并运行 java -jar... 时,它可以正常工作。但是,如果您通过 JavaFX 插件运行它,则不会,因为您的类路径 (target/classes) 中没有清单,即使您拥有它,也不会被访问。本机图像的 GluonFX 插件也以这种方式工作。如果您为核心代码创建一个 jar,并将其作为依赖项添加到主项目,那么这将起作用。但它会增加额外的复杂性(多模块项目)。在这种情况下,使用资源插件似乎更加简单方便。

标签: java javafx graalvm graalvm-native-image gluonfx


【解决方案1】:

假设您有一个 Maven 项目并添加到您的主应用程序类:

@Override
public void start(Stage primaryStage) throws Exception {
    ...
    System.out.println("Main class version: " + getClass().getPackage().getImplementationVersion());
}

如果你用 shade 插件做了一个胖罐子,并注意添加所需的清单条目,如 Implementation-Version(比如说 1.0),当你运行时:

java --module-path=PATH_TO_FX --add-modules javafx.controls,javafx.fxml -jar my-fat-jar.jar

应该打印出来:

Main class version: 1.0

但是如果你运行

mvn javafx:run

打印出来:

Main class version: null

正如你所报告的那样。

原因:类路径中没有清单,并且类(target/classes)没有打包在jar中。

如果您的项目有第三方依赖项,其中包含带有 Implementation-Version 条目的清单(比如说 2.0),请执行以下操作:

@Override
public void start(Stage primaryStage) throws Exception {
    ...
    System.out.println("3rd party Main class version: " + com.my.third.party.MainClass.class.getPackage().getImplementationVersion());
}

会起作用:

mvn javafx:run
[INFO] --- javafx-maven-plugin:0.0.8:run (default-cli) @ MyProject ---
3rd party Main class version: 2.0.

因为 jar 是带有清单的打包类的依赖项。

并且做原生图像mvn gluonfx:build gluonfx:nativerun 也可以:

[INFO] --- gluonfx-maven-plugin:1.0.10:nativerun (default-cli) @ MyProject ---
[Mon Dec 20 21:29:16 CET 2021][INFO] ==================== RUN TASK ====================
[Mon Dec 20 21:29:16 CET 2021][INFO] [SUB] 2021-12-20 21:29:16.810 MyProject[23068:414510] Starting Gluon VM...
[Mon Dec 20 21:29:16 CET 2021][INFO] [SUB] Dec 20, 2021 9:29:16 PM com.sun.javafx.application.PlatformImpl startup
[Mon Dec 20 21:29:16 CET 2021][INFO] [SUB] WARNING: Unsupported JavaFX configuration: classes were loaded from 'unnamed module @21c815e4'
[Mon Dec 20 21:29:16 CET 2021][INFO] [SUB] 3rd party Main class version: 2.0

所以此时我看到了三个选项:

  • 将核心代码移动到模块中,发布 jar,并将其作为依赖项添加到主项目中,这样应该可以工作。
  • 将清单键值移动到属性文件,并使用 Maven 资源插件。这应该与 GluonFX 插件一起使用(确保将属性扩展添加到资源列表)。这应该是最简单的。
  • 在 Substrate 上提交 issue 以请求清单。 到目前为止,Substrate 从项目 classes 创建了一个 jar,所以理论上它也可以有一个清单,并且可以使用来自插件配置的一些键值来归档。添加清单很容易,问题在于将更改添加到配置以传递键值。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-08-31
    • 2022-12-18
    • 1970-01-01
    • 1970-01-01
    • 2020-04-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多