Retrieve version from maven pom.xml in code

Viewed 245276

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

15 Answers

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
    <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>

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

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).

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();

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.

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:

project.version=@project.version@
project.artifactId=@project.artifactId@

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

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

I hope this helps!

Related