picocli
picocli copied to clipboard
DOC: improve example/docs getting version from jar manifest
As suggested by @rileynull in https://github.com/remkop/picocli/issues/236#issuecomment-1105308193, the example showing how to get version information from the manifest may be overly convoluted.
TODO: Experiment with this and update the docs if this works as expected.
(Potential example for the manual:
class ManifestBasedVersionProviderWithVariables implements IVersionProvider {
public String[] getVersion() {
String version = getClass().getPackage().getImplementationVersion();
return new String[] { "${COMMAND-FULL-NAME} version " + version };
}
}
Note that the Class.getPackage
method returns a Package
object that is populated with information from the manifest (the /META-INF/MANIFEST.MF
file in the jar file). If the Class
that is being inspected is not in a jar that has a /META-INF/MANIFEST.MF
file, the getPackage
method returns null
.
This should be mentioned in the documentation.
If the
Class
that is being inspected is not in a jar that has a/META-INF/MANIFEST.MF
file, thegetPackage
method returnsnull
.
And also if that MANIFEST.MF exists, but does not have the Implementation-Version property. Which happens to be the default for Maven's Archiver: https://maven.apache.org/shared/maven-archiver/index.html#class_manifest
Some observations from my end:
-
When I still had a non-modular Java project, I could read my project title and version from the manifest file using the code @remkop mentioned above:
String title = getClass().getPackage().getImplementationTitle(); String version = getClass().getPackage().getImplementationVersion();
-
The above approach failed when I wrapped all my code in a Java module. Both
getImplementation...()
calls returnednull
, and I could not find a way around it. Following the example from VersionProvider2.java, I could again read my project version (if I specified my implementation title instead of"picocli"
, of course). -
I just found an alternative to VersionProvider2.java that is much shorter and seems to work well for modular Java code:
-
Set the module version using the
--module-version
parameter ofjavac
. With Gradle, a (Kotlin DSL) task definition like the following does the job:tasks { compileJava { options.javaModuleVersion.set("${project.version}") } }
-
In the
IVersionProvider
implementation, read the module version from theModuleDescriptor
:String version = ""; ModuleDescriptor moduleDescriptor = getClass().getModule().getDescriptor(); if (moduleDescriptor != null) { Optional<ModuleDescriptor.Version> optional = moduleDescriptor.version(); if (optional.isPresent()) { version = optional.get().toString(); } }
-
I'm not sure if approach 1 really can't be adapted for modular code. Neither can I ensure approach 3 always works. But hopefully, someone else can step in and explain if approach 3 is a viable alternative to VersionProvider2.java for modular code.