Version Informations Into Your Apps With Maven
It often happens having an application and you want to show a version information in
a kind of About Dialog
or may be on command line as well
(probably you know --version
stuff).
So in relationship with Maven the question is: How to get this into your Java code.
There are in general four ways to do it:
-
Using the pom.properties file which is created by default by Maven.
-
Using the information which is provided by the
MANIFST.MF
file. There are several ways to get those information. -
Create a property which is filtered during the build process and will be read by your application.
-
Using a generated class which contains the appropriate informations.
#Using the pom.properties#
In every Maven build a property pom.properties is packaged into resulting archive (jar, ear, war, ejb etc.) which can be found under the following location:
1META-INF/maven/${groupId}/${artifactId}/pom.properties
This file contains the following entries
1version=${project.version}
2groupId=${project.groupId}
3artifactId=${project.artifactId}
They can be extracted by Java code like the following:
1public class TheVersionClass
2{
3 ..
4
5 public TheVersionClass()
6 {
7 InputStream resourceAsStream =
8 this.getClass().getResourceAsStream(
9 "/META-INF/maven/com.soebes.examples/version-examples-i/pom.properties"
10 );
11 this.prop = new Properties();
12 try
13 {
14 this.prop.load( resourceAsStream );
15 }
16 ...
17 }
18}
The disadvantage of this approach
is that you can not simply enhance the entries which are stored in the pom.properties
file. For
such a purpose you need to define your own pom.properties
file.
#The MANIFEST.MF File#
In Java there exists a possibility to extract information from the MANIFEST.MF
by using simple code lines
like the following:
1public class TheVersionClass {
2 public TheVersionClass() {
3 System.out.println( " Implementation Title:" + this.getClass().getPackage().getImplementationTitle() );
4 System.out.println( " Implementation Vendor:" + this.getClass().getPackage().getImplementationVendor() );
5 System.out.println( "Implementation Version:" + this.getClass().getPackage().getImplementationVersion() );
6 System.out.println( " Specification Tile:" + this.getClass().getPackage().getSpecificationTitle() );
7 System.out.println( " Specification Vendor:" + this.getClass().getPackage().getSpecificationVendor() );
8 System.out.println( " Specification Version:" + this.getClass().getPackage().getSpecificationVersion() );
9 }
10}
But unfortunately within a Maven build this will result usually in null output, cause by default
these information are not written to the MANIFEST.MF
file. This can simply be fixed by
using the following pom snippet:
1<build>
2 <pluginManagement>
3 <plugins>
4 <plugin>
5 <artifactId>maven-jar-plugin</artifactId>
6 <configuration>
7 <archive>
8 <manifest>
9 <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
10 <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
11 </manifest>
12 </archive>
13 </configuration>
14 </plugin>
15 </plugins>
16 </pluginManagement>
17</build>
The main disadvantage of this approach is that you can only use the Implementation
and
Specification
parts of your MANIFEST.MF
file which might be enough in some situations
but not in all.
#The Filtered Property File#
Apart from the above methods you can of course define a simple version.properties
file within src/main/resources
with any contens you like:
1version=${project.version}
2groupId=${project.groupId}
3artifactId=${project.artifactId}
You need to setup filtering in your project like this:
1<build>
2 <resources>
3 <resource>
4 <directory>src/main/resources</directory>
5 <includes>
6 <include>version.properties</include>
7 </includes>
8 <filtering>true</filtering>
9 </resource>
10 </resources>
11</build>
The entries can be extracted by Java code like the following which is more or less exactly the same as before (except for the path):
1public class TheVersionClass
2{
3 ..
4
5 public TheVersionClass()
6 {
7 InputStream resourceAsStream =
8 this.getClass().getResourceAsStream(
9 "/version.properties"
10 );
11 this.prop = new Properties();
12 try
13 {
14 this.prop.load( resourceAsStream );
15 }
16 ...
17 }
18}
#The Generated Class#
You can use the templating-maven-plugin which can be used to create a class which contains the appropriate informations.
The first step is to create a template file within the following location src/main/java-templates
like the following:
1public final class Version {
2
3 private static final String VERSION = "${project.version}";
4 private static final String GROUPID = "${project.groupId}";
5 private static final String ARTIFACTID = "${project.artifactId}";
6 private static final String REVISION = "${buildNumber}";
7
8 public static String getVersion() {
9 return VERSION;
10 }
11 // other getters...
12}
This class can contain any reference to properties or project related information which
you can access via the ${project...}
etc.
The ${buildNumber}
is an example for using other placeholders which in this case
is filled by the buildnumber-maven-plugin
which usually provides the SVN/Git revision number.
The following pom snippet is used to generate the Java source from the Java template file and make sure it will be compiled by the maven-compiler-plugin.
1<plugins>
2 <plugin>
3 <groupId>org.codehaus.mojo</groupId>
4 <artifactId>templating-maven-plugin</artifactId>
5 <version>1.0.0</version>
6 <executions>
7 <execution>
8 <id>generate-verion-class</id>
9 <goals>
10 <goal>filter-sources</goal>
11 </goals>
12 </execution>
13 </executions>
14 </plugin>
15</plugins>
So based on the given information you see there are several ways to get the problem solved. It depends you which you decide to use. All the above examples can be found on github repository with running integration tests to show the results.