简体   繁体   中英

Maven 2: How to package current project version in a WAR file?

I am using Maven 2 to build my Java project and I am looking for a way to present the current version number of the pom.xml to the user (using a Servlet or JSP for example).

As far as I can see, the best way would be that Maven packages the version number as a text file into the WAR. This allows me to read the version from that file and present it the way I want.

Does anyone know of a plugin that can do something like that for me? Maybe the WAR plugin can be configured to do so? Or maybe using some other approach all together?

I solved this problem a little differently, as I had a desire to display version, svn revision, etc. on the index page of a service. I used the buildnumber-maven-plugin and the war-plugin to store the values in the manifest.

pom.xml snippet:

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>buildnumber-maven-plugin</artifactId>
    <executions>
      <execution>
        <phase>validate</phase>
        <goals>
          <goal>create</goal>
        </goals>
      </execution>
    </executions>
  </plugin>
  <plugin>
    <artifactId>maven-war-plugin</artifactId>
    <configuration>
      <archive>
        <manifest>
          <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
        </manifest>
        <manifestEntries>
          <Implementation-Environment>${env}</Implementation-Environment>
          <Implementation-Build>${buildNumber}</Implementation-Build>
        </manifestEntries>
      </archive>
    </configuration>
    <executions>
      <execution>
        <phase>package</phase>
        <goals>
          <goal>war</goal>
        </goals>
        <configuration>
          <classifier>${env}</classifier>
        </configuration>
      </execution>
    </executions>
  </plugin>

The JSP to pull them out was fairly trivial:

<%@ page language="java" pageEncoding="UTF-8"%>
<% 
java.util.jar.Manifest manifest = new java.util.jar.Manifest();
manifest.read(pageContext.getServletContext().getResourceAsStream("/META-INF/MANIFEST.MF"));
java.util.jar.Attributes attributes = manifest.getMainAttributes();

%>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
    <title>Health Check</title>
  </head>
  <body>
    <h1>Health Check</h1>
    <h2>Version: <%=attributes.getValue("Implementation-Version")%>-<%=attributes.getValue("Implementation-Environment")%></h2>
    <h2>SVN Revision: <%=attributes.getValue("Implementation-Build")%></h2>
  </body>
</html>

This displayed something like:

Version: 2.0.1-SNAPSHOT-QA

SVN Revision: 932

Of course, variables can be included in resources and filtered wih the maven-resource-plugin by adding a <filtering> tag to the POM and set it to true like this:

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

And you could use this feature to read and replace ${version} (or ${project.version} or ${pom.version} which are equivalent) in a properties file for example.

But, actually, the information you are looking for is available by default by Maven (unless you configured it to not do so which is very unlikely if you are not aware of that). If you unpack the WAR that Maven created for you and take a look at it you would see the following:

|-- META-INF
|   |-- MANIFEST.MF
|   `-- maven
|       `-- com.mycompany.app
|           `-- my-app
|               |-- pom.properties
|               `-- pom.xml
|-- WEB-INF
|   |-- classes
|   |   |-- ...
|   |-- lib
|   |   |-- ...
|   `-- web.xml
|-- bar.jsp
|-- ...
`-- foo.jsp

As you can see, you'll find a pom.xm and pom.properties file in it and, as explained in How do I add resources to my JAR? :

The pom.xml and pom.properties files are packaged up in the JAR so that each artifact produced by Maven is self-describing and also allows you to utilize the metadata in your own application if the need arises. One simple use might be to retrieve the version of your application. Operating on the POM file would require you to use some Maven utilities but the properties can be utilized using the standard Java API and look like the following:

 #Generated by Maven #Tue Oct 04 15:43:21 GMT-05:00 2005 version=1.0-SNAPSHOT groupId=com.mycompany.app artifactId=my-app 

So you could just load this pom.properties file with something like this (pseudo code):

// Retrieve resource
InputStream is = getClass().getResourceAsStream( "/META-INF/maven/com.mycompany.app/my-app/pom.properties" );

// Do something with the resource, e.g. load it as Properties
Properties prop = new Properties();
prop.load(is);
String version = prop.getProperty("version");

My solution for the standard Maven WAR plugin

Add a resources tag to you build section which enables filtering (aka "search and replace"):

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

Then in your src/main/resources add a version.properties file containing any filter variables that matches one of the standard maven build variables (you can also use filtering feature to load your own custom variables):

pom.version=${pom.version}

Now when you do a "maven package" or a maven install it will copy the version.properties file into the WEB-INF/classes and do a search and replace to add the pom version into the file.

To get at this with Java use a class such as:

public class PomVersion {
    final private static Logger LOGGER = LogManager.getLogger(PomVersion.class);

    final static String VERSION = loadVersion();

    private static String loadVersion() {
        Properties properties = new Properties();
        try {
            InputStream inStream = PomVersion.class.getClassLoader().getResourceAsStream("version.properties");
            properties.load(inStream);
        } catch (Exception e){
            LOGGER.warn("Unable to load version.properties using PomVersion.class.getClassLoader().getResourceAsStream(...)", e);
        }
        return properties.getProperty("pom.version");
    }

    public static String getVersion(){
        return VERSION;
    }
}

Now you can just call PomVersion.getVersion() to put the version number of the pom file into the page. You can also have the WAR file be given the same number by using a filter variable in the finalName within the pom.xml:

<build>
    <finalName>my-killer-app-${pom.version}</finalName>
...
</build>

so now if you set your application version in your pom to be 01.02.879:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.killer.app</groupId>
    <artifactId>my-killer-app</artifactId>
    <packaging>war</packaging>
    <name>This App Will Rule The World</name>
    <version>01.02.879</version>
    ...
</project>

when you do an "mvn install" the war file name include the version number also:

my-killer-app-01.02.879.war

finally if you use Spring heavily such as with SpringMVC/SpringWebFlow you can make a singleton service bean which uses that class to avoid having to reference the low level class by name:

@Service("applicationVersion")
public class ApplicationVersion {
    final static String VERSION = PomVersion.getVersion();

    public String getVersion() {
        return VERSION;
    }
}

You're looking to do filtering of resources. This is done even before the war-plugin creates the file. I'm pretty sure the war-plugin packs the version in the web.xml and manifest, but I'm not sure how to access those through servlet APIs, but it might also be a valid approach.

Have a look at the Maven resource plugin documentation, it'll tell you how it's done. I think you should be able to just substitue the version using ${version} . Haven't got a working maven installation to test it here though.

Among the answers we see a few variations of the "load a properties file" method and I'm going to append to that with yet another alternative version that works with Maven 3.5 , but probably also with older versions.


Step 0 the pom.xml

You only need to do one thing in the pom.xml ; turn on something called resource filtering . This is easily done by finding the <build> tag and placing your resource folder which you wish to filter in there. It will look like follows:

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

Note: the elipsis ... means code is being omitted

if you want to, you may also add your custom variables, but this is not necessary :

<project ...>
  <properties>
    <build.version>1.1-SNAPSHOT</build.version>
  </properties>
  ...
</project>


Step 1 the properties file

Create a .properties file and place it in your maven resources file. I'm going to call mine application.properties . For simplicity I'm going to put it in the default resources folder; src/main/resources but you can edit that to pretty much any folder you'd like.

|-- pom.xml
|-- src
   |-- main
      |-- java
      |-- webapp
      |-- resources
         `-- application.properties

In the application.properties file I'm going to add the version property I want:

author=eFox
build=${build.version}
version=${project.version} # This is the default maven variable that you could and should use.


Step 2 the *.JSP page

This is where my method differs from the above mentioned versions. Instead of loading the properties file as a Property class, load the META-INF pom.properties or make this a controller class, the we're going to load it as a resource:

<%@ page import = "java.util.ResourceBundle" %> 
<% ResourceBundle resource = ResourceBundle.getBundle("application");
  String version = resource.getString("version");
  String author = resource.getString("author");%>
<html>
  <head>
    ...
  </head>
  <body>
    ...
    Site version: <%=version %> by <%=author%>
  </body>
</html>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM