337

What is the simplest way to retrieve version number from maven's pom.xml in code, i.e., programatically?

16 Answers 16

338

Assuming you're using Java, you can:

  1. Create a .properties file in (most commonly) your src/main/resources directory (but in step 4 you could tell it to look elsewhere).

  2. Set the value of some property in your .properties file using the standard Maven property for project version:

    foo.bar=${project.version}
    
  3. In your Java code, load the value from the properties file as a resource from the classpath (google for copious examples of how to do this, but here's an example for starters).

  4. In Maven, enable resource filtering. This will cause Maven to copy that file into your output classes and translate the resource during that copy, interpreting the property. You can find some info here but you mostly just do this in your pom:

    <build>
      <resources>
        <resource>
          <directory>src/main/resources</directory>
          <filtering>true</filtering>
        </resource>
      </resources>   
    </build>
    

You can also get to other standard properties like project.name, project.description, or even arbitrary properties you put in your pom <properties>, etc. Resource filtering, combined with Maven profiles, can give you variable build behavior at build time. When you specify a profile at runtime with -PmyProfile, that can enable properties that then can show up in your build.

5
  • 3
    I found a code this that no change Maven config.
    – Wendel
    Commented Jul 8, 2016 at 14:30
  • 15
    Beware of using filtering directly on src/main/resources, as this may process all files located in this directory, including binaries files. To avoid unpredictable behaviours, it's better to do filtering on a src/main/resources-filtered directory, as suggested here. Anyway, thank you for this nice trick!
    – SiZiOUS
    Commented Sep 13, 2018 at 12:12
  • 2
    The answer below using the MavenXppReader to get the actual model is really useful, as it doesn't need to run anything to find the value. In cases where you need to know the version before anything is run, look at the answers below; it was very helpful for me to let gradle know what version a checked out maven project has, so I could know the output jar location beforehand.
    – Ajax
    Commented Feb 21, 2019 at 22:39
  • Beware that this does not work if using it during unit testing. If you need the project information during unit testing see answer by @kriegaex
    – ormurin
    Commented Mar 4, 2021 at 8:54
  • 7
    From here, if you are using spring boot, you need to use @project.version@ instead of ${project.version}
    – Vivere
    Commented Apr 23, 2021 at 21:36
134

The accepted answer may be the best and most stable way to get a version number into an application statically, but does not actually answer the original question: How to retrieve the artifact's version number from pom.xml? Thus, I want to offer an alternative showing how to do it dynamically during runtime:

You can use Maven itself. To be more exact, you can use a Maven library.

<dependency>
  <groupId>org.apache.maven</groupId>
  <artifactId>maven-model</artifactId>
  <version>3.3.9</version>
</dependency>

And then do something like this in Java:

package de.scrum_master.app;

import org.apache.maven.model.Model;
import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;

import java.io.FileReader;
import java.io.IOException;

public class Application {
    public static void main(String[] args) throws IOException, XmlPullParserException {
        MavenXpp3Reader reader = new MavenXpp3Reader();
        Model model = reader.read(new FileReader("pom.xml"));
        System.out.println(model.getId());
        System.out.println(model.getGroupId());
        System.out.println(model.getArtifactId());
        System.out.println(model.getVersion());
    }
}

The console log is as follows:

de.scrum-master.stackoverflow:my-artifact:jar:1.0-SNAPSHOT
de.scrum-master.stackoverflow
my-artifact
1.0-SNAPSHOT

Update 2017-10-31: In order to answer Simon Sobisch's follow-up question I modified the example like this:

package de.scrum_master.app;

import org.apache.maven.model.Model;
import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Application {
  public static void main(String[] args) throws IOException, XmlPullParserException {
    MavenXpp3Reader reader = new MavenXpp3Reader();
    Model model;
    if ((new File("pom.xml")).exists())
      model = reader.read(new FileReader("pom.xml"));
    else
      model = reader.read(
        new InputStreamReader(
          Application.class.getResourceAsStream(
            "/META-INF/maven/de.scrum-master.stackoverflow/aspectj-introduce-method/pom.xml"
          )
        )
      );
    System.out.println(model.getId());
    System.out.println(model.getGroupId());
    System.out.println(model.getArtifactId());
    System.out.println(model.getVersion());
  }
}
4
  • 2
    This is nearly identical to what I use and works fine when started from eclipse, but doesn't when started from the normal packaged jar (dependency classes aren't integrated) and doesn't work when packaged with maven-assembly-plugin jar-with-dependencies I get a java.io.FileNotFoundException: pom.xml (it is in the final jar as META-INF/maven/my.package/myapp/pom.xml) - any hints how to solve this? Commented Oct 28, 2017 at 15:36
  • 1
    My solution is meant to work dynamically in development environments, e.g. when used in tests or tools started from IDE or console. The accepted answer to this question shows several ways to package the version number statically into your artifacts. I was not assuming that pom.xml would be available within JARs at all. Nice for you that you have it there, though. Maybe you could just adjust the path when opening the file reader and maybe make it dependent on the classloader situation. I would have to try for myself. Feel free to ask follow-up questions if this does not help.
    – kriegaex
    Commented Oct 31, 2017 at 12:12
  • 2
    Hi @SimonSobisch, I have just updated my answer so as to show you how to do what you want. But please be aware of the fact that I just did it quick & dirty, I do not particularly like the code with the nested constructors.
    – kriegaex
    Commented Oct 31, 2017 at 12:52
  • I'm just extending a tool so it can lookup usages of specific artifacts in repository directory trees and already included maven-model. Now I know how to use it, thanks :)
    – Gunnar
    Commented Jan 4, 2022 at 13:07
81

Packaged artifacts contain a META-INF/maven/${groupId}/${artifactId}/pom.properties file which content looks like:

#Generated by Maven
#Sun Feb 21 23:38:24 GMT 2010
version=2.5
groupId=commons-lang
artifactId=commons-lang

Many applications use this file to read the application/jar version at runtime, there is zero setup required.

The only problem with the above approach is that this file is (currently) generated during the package phase and will thus not be present during tests, etc (there is a Jira issue to change this, see MJAR-76). If this is an issue for you, then the approach described by Alex is the way to go.

3
60

There is also the method described in Easy way to display your apps version number using Maven:

Add this to pom.xml

<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-jar-plugin</artifactId>
      <configuration>
        <archive>
          <manifest>
            <mainClass>test.App</mainClass>
            <addDefaultImplementationEntries>
              true
            </addDefaultImplementationEntries>
          </manifest>
        </archive>
      </configuration>
    </plugin>
  </plugins>
</build>

Then use this:

App.class.getPackage().getImplementationVersion()

I have found this method to be simpler.

6
  • 18
    -1 - This solution didn't work for me; the value of getImplementationVersion() was null. (maven version 3.0.4)
    – Jesse Webb
    Commented Feb 17, 2013 at 21:04
  • 9
    depending on the phase... only works when the artifact is being packaged, so does not work on unit tests :-/
    – wikier
    Commented Dec 16, 2013 at 15:32
  • 5
    For .war artifacts, remember to use maven-war-plugin instead of maven-jar-plugin
    – cs_pupil
    Commented Nov 30, 2017 at 18:28
  • For me, this does work in Tomcat 8, but doesn't work in Tomcat 7 (getImplementationVersion() returns null). Commented Feb 14, 2018 at 17:25
  • 3
    It works when you compile a jar, otherwise doesn't
    – SkyDancer
    Commented Feb 23, 2022 at 21:19
27

If you use mvn packaging such as jar or war, use:

getClass().getPackage().getImplementationVersion()

It reads a property "Implementation-Version" of the generated META-INF/MANIFEST.MF (that is set to the pom.xml's version) in the archive.

2
  • 1
    If looking for how to include "Implementation-Version" to MANIFEST.MF: stackoverflow.com/questions/921667/…
    – Wortig
    Commented Jul 4, 2021 at 15:20
  • This seems to be an incomplete answer that only applies to certain situations. Did not work for my TestNG project, probably due to lacking manifest packaging.
    – MarkHu
    Commented Sep 3, 2021 at 21:38
23

To complement what @kieste has posted, which I think is the best way to have Maven build informations available in your code if you're using Spring-boot: the documentation at http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#production-ready-application-info is very useful.

You just need to activate actuators, and add the properties you need in your application.properties or application.yml

Automatic property expansion using Maven

You can automatically expand info properties from the Maven project using resource filtering. If you use the spring-boot-starter-parent you can then refer to your Maven ‘project properties’ via @..@ placeholders, e.g.

project.artifactId=myproject
project.name=Demo
project.version=X.X.X.X
project.description=Demo project for info endpoint
[email protected]@
[email protected]@
[email protected]@
[email protected]@
1
  • 1
    This answer helped in that I needed to use the @..@ notation to read the properties from maven. Something else is using the ${..} notation and it was conflicting.
    – Crompy
    Commented Nov 18, 2020 at 2:25
16

When using spring boot, this link might be useful: https://docs.spring.io/spring-boot/docs/2.3.x/reference/html/howto.html#howto-properties-and-configuration

With spring-boot-starter-parent you just need to add the following to your application config file:

# get values from pom.xml
[email protected]@

After that the value is available like this:

@Value("${pom.version}")
private String pomVersion;
2
11

Sometimes the Maven command line is sufficient when scripting something related to the project version, e.g. for artifact retrieval via URL from a repository:

mvn help:evaluate -Dexpression=project.version -q -DforceStdout

Usage example:

VERSION=$( mvn help:evaluate -Dexpression=project.version -q -DforceStdout )
ARTIFACT_ID=$( mvn help:evaluate -Dexpression=project.artifactId -q -DforceStdout )
GROUP_ID_URL=$( mvn help:evaluate -Dexpression=project.groupId -q -DforceStdout | sed -e 's#\.#/#g' )
curl -f -S -O http://REPO-URL/mvn-repos/${GROUP_ID_URL}/${ARTIFACT_ID}/${VERSION}/${ARTIFACT_ID}-${VERSION}.jar
2
  • 1
    It's fine, just incredibly slow, especially if the artifacts aren't downloaded yet.
    – ingyhere
    Commented Sep 2, 2020 at 7:09
  • I completely agree with that :-( The only advantage is that it works with every kind of Maven project/module, even those which inherit their version from some parent pom.xml
    – t0r0X
    Commented Sep 2, 2020 at 7:30
6

Use this Library for the ease of a simple solution. Add to the manifest whatever you need and then query by string.

 System.out.println("JAR was created by " + Manifests.read("Created-By"));

http://manifests.jcabi.com/index.html

5
            <build>
                <finalName>${project.artifactId}-${project.version}</finalName>
                <pluginManagement>
                    <plugins>
                        <plugin>
                            <groupId>org.apache.maven.plugins</groupId>
                            <artifactId>maven-war-plugin</artifactId>
                            <version>3.2.2</version>
                            <configuration>
                                <failOnMissingWebXml>false</failOnMissingWebXml>
                                <archive>
                                    <manifest>
                                        <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
                                        <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
                                    </manifest>
                                </archive>
                            </configuration>
                        </plugin>
                     </plugins>
                </pluginManagement>
            </build>

Get Version using this.getClass().getPackage().getImplementationVersion()

PS Don't forget to add:

<manifest>
    <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
    <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
</manifest>
1
  • Thank you . This worked for my project in RapidClipse / Vaadin + Maven 3.6.3
    – Imeksbank
    Commented Oct 13, 2020 at 10:56
4

Step 1: If you are using Spring Boot, your pom.xml should already contain spring-boot-maven-plugin. You just need to add the following configuration.

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <executions>
        <execution>
            <id>build-info</id>
            <goals>
                <goal>build-info</goal>
            </goals>
        </execution>
    </executions>
</plugin>

It instructs the plugin to execute also build-info goal, which is not run by default. This generates build meta-data about your application, which includes artifact version, build time and more.

Step2: Accessing Build Properties with buildProperties bean. In our case we create a restResource to access to this build info in our webapp

@RestController
@RequestMapping("/api")
public class BuildInfoResource {
    @Autowired
    private BuildProperties buildProperties;

    
    @GetMapping("/build-info")
    public ResponseEntity<Map<String, Object>> getBuildInfo() {
        Map<String, String> buildInfo = new HashMap();
        buildInfo.put("appName", buildProperties.getName());
        buildInfo.put("appArtifactId", buildProperties.getArtifact());
        buildInfo.put("appVersion", buildProperties.getVersion());
        buildInfo.put("appBuildDateTime", buildProperties.getTime());
        return ResponseEntity.ok().body(buldInfo);
    }
}

I hope this will help

4

It's very easy and no configuration is needed if you use Spring with Maven. According to the “Automatic Property Expansion Using Maven” official documentation you can automatically expand properties from the Maven project by using resource filtering. If you use the spring-boot-starter-parent, you can then refer to your Maven ‘project properties’ with @..@ placeholders, as shown in the following example:

[email protected]@
[email protected]@

And you can retrieve it with @Value annotation in any class:

@Value("${project.artifactId}@${project.version}")
private String RELEASE;

I hope this helps!

3

I had the same problem in my daytime job. Even though many of the answers will help to find the version for a specific artifact, we needed to get the version for modules/jars that are not a direct dependency of the application. The classpath is assembled from multiple modules when the application starts, the main application module has no knowledge of how many jars are added later.

That's why I came up with a different solution, which may be a little more elegant than having to read XML or properties from jar files.

The idea

  1. use a Java service loader approach to be able to add as many components/artifacts later, which can contribute their own versions at runtime. Create a very lightweight library with just a few lines of code to read, find, filter and sort all of the artifact versions on the classpath.
  2. Create a maven source code generator plugin that generates the service implementation for each of the modules at compile time, package a very simple service in each of the jars.

The solution

Part one of the solution is the artifact-version-service library, which can be found on github and MavenCentral now. It covers the service definition and a few ways to get the artifact versions at runtime.

Part two is the artifact-version-maven-plugin, which can also be found on github and MavenCentral. It is used to have a hassle-free generator implementing the service definition for each of the artifacts.

Examples

Fetching all modules with coordinates

No more reading jar manifests, just a simple method call:

// iterate list of artifact dependencies
for (Artifact artifact : ArtifactVersionCollector.collectArtifacts()) {
    // print simple artifact string example
    System.out.println("artifact = " + artifact);
}

A sorted set of artifacts is returned. To modify the sorting order, provide a custom comparator:

new ArtifactVersionCollector(Comparator.comparing(Artifact::getVersion)).collect();

This way the list of artifacts is returned sorted by version numbers.

Find a specific artifact

ArtifactVersionCollector.findArtifact("de.westemeyer", "artifact-version-service");

Fetches the version details for a specific artifact.

Find artifacts with matching groupId(s)

Find all artifacts with groupId de.westemeyer (exact match):

ArtifactVersionCollector.findArtifactsByGroupId("de.westemeyer", true);

Find all artifacts where groupId starts with de.westemeyer:

ArtifactVersionCollector.findArtifactsByGroupId("de.westemeyer", false);

Sort result by version number:

new ArtifactVersionCollector(Comparator.comparing(Artifact::getVersion)).artifactsByGroupId("de.", false);

Implement custom actions on list of artifacts

By supplying a lambda, the very first example could be implemented like this:

ArtifactVersionCollector.iterateArtifacts(a -> {
    System.out.println(a);
    return false;
});

Installation

Add these two tags to all pom.xml files, or maybe to a company master pom somewhere:

<build>
  <plugins>
    <plugin>
      <groupId>de.westemeyer</groupId>
      <artifactId>artifact-version-maven-plugin</artifactId>
      <version>1.1.0</version>
      <executions>
        <execution>
          <goals>
            <goal>generate-service</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

<dependencies>
  <dependency>
    <groupId>de.westemeyer</groupId>
    <artifactId>artifact-version-service</artifactId>
    <version>1.1.0</version>
  </dependency>
</dependencies>

Feedback

It would be great if maybe some people could give the solution a try. Getting feedback about whether you think the solution fits your needs would be even better. So please don't hesitate to add a new issue on any of the github projects if you have any suggestions, feature requests, problems, whatsoever.

Licence

All of the source code is open source, free to use even for commercial products (MIT licence).

3
  • This is cool, going to give it a try
    – jj33
    Commented Dec 5, 2021 at 14:36
  • Great, let me know if it works for you! Commented Dec 5, 2021 at 18:05
  • Hey @jj33, I have created a new release to include additional fields as you suggested on github. Hope it turns out to be useful for you! Commented Dec 14, 2021 at 21:19
0

With reference to ketankk's answer:

Unfortunately, adding this messed with how my application dealt with resources:

<build>
  <resources>
    <resource>
      <directory>src/main/resources</directory>
      <filtering>true</filtering>
    </resource>
  </resources>   
</build>

But using this inside maven-assemble-plugin's < manifest > tag did the trick:

<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>

So I was able to get version using

String version = getClass().getPackage().getImplementationVersion();
0

Preface: Because I remember this often referred-to question after having answered it a few years ago, showing a dynamic version actually accessing Maven POM infos dynamically (e.g. also during tests), today I found a similar question which involved accessing module A's Maven info from another module B.

I thought about it for a moment and spontaneously had the idea to use a special annotation, applying it to a package declaration in package-info.java. I also created a multi-module example project on GitHub. I do not want to repeat the whole answer, so please see solution B in this answer. The Maven setup involves Templating Maven Plugin, but could also be solved in a more verbose way using a combination of resource filtering and adding generated sources directory to the build via Build Helper Maven. I wanted to avoid that, so I simply used Templating Maven.

0

Accepted answer worked for me once in the step #2 I changed ${project.version} to ${pom.version}

2

Not the answer you're looking for? Browse other questions tagged or ask your own question.