Issue
I have a JavaFX-based desktop app, for which I create native images via GraalVM/GluonFX. To retrieve the version of the app during runtime, I previously – when there was only a fat JAR of the app – used Package#getImplementationVersion()
. However, this returns null
.
I assume this is because I don't set the manifest entries properly? My configuration of the 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>
Is there a way to configure the plugin such that Package#getImplementationVersion()
returns the app's version? I wasn't able to find something in the corresponding documentation. Also, a related issue in GraalVM has been resolved in 2020.
Solution
Let say you have a Maven project and you add to your main Application class:
@Override
public void start(Stage primaryStage) throws Exception {
...
System.out.println("Main class version: " + getClass().getPackage().getImplementationVersion());
}
If you do a fat jar with the shade plugin and take care of adding the required manifest entries like Implementation-Version
(let's say 1.0
), when you run:
java --module-path=PATH_TO_FX --add-modules javafx.controls,javafx.fxml -jar my-fat-jar.jar
it should print:
Main class version: 1.0
However if you run
mvn javafx:run
it prints:
Main class version: null
as you have reported.
The reason for this: there is no manifest in the classpath, and the classes (target/classes
) are not packed in a jar.
If your project has a third party dependency that includes a manifest with an Implementation-Version
entry (let's say 2.0
), doing:
@Override
public void start(Stage primaryStage) throws Exception {
...
System.out.println("3rd party Main class version: " + com.my.third.party.MainClass.class.getPackage().getImplementationVersion());
}
will work:
mvn javafx:run
[INFO] --- javafx-maven-plugin:0.0.8:run (default-cli) @ MyProject ---
3rd party Main class version: 2.0.
because the jar is a dependency of packed classes with a manifest.
And doing the native image mvn gluonfx:build gluonfx:nativerun
also works:
[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
So at this point I see three options:
- Move your core code to a module, publish a jar, and add it to your main project as a dependency, that should work.
- Move your manifest key-values to a properties file, and use the Maven resources plugin. That should work out of the box with the GluonFX plugin (make sure you add the properties extension to the resources List). This should be the easiest one.
- File an issue on Substrate to ask for a manifest. So far, Substrate creates a jar out of the project classes, so in theory it could also have a manifest, and it could be filed with some key-values coming from the plugin's configuration. Adding the manifest is easy, the problem is adding the changes to the configuration to pass down the key-values.
Answered By - José Pereda