Automatically adding version information into a Java Manifest file with Ant

23.04.2006 @ 13.38, Posted in Java

Taged with , ,

Version information is important for applications and libraries alike. Somebody using your jar file (be it an application, a library or a part of a larger framework) should be able to tell which version of your program they are using. Equally, giving the users that information should be as little effort for the developer as possible. Some library authors solve this by creating versions of their libraries with the version information in the filename (for example, avalon-excalibur-vm14-20020705.jar, which happened to linger around in a lib directory I have open in my shell, so I used as an example), but this approach is not working very well for applications. Besides, using “versioned” filenames has its own problems (no drop-in replacement of newer versions because the classpath needs to be changed).

Another way to give the users informations about what version of a jar file they are using is to store it in the jar file itself, in a file called the manifest, which is present in all jar files.

This little tutorial shows you how to automatically generate the manifest for your jar file and access the information later on in your Java program (for example, in an “About” dialog). The insertion of the version information will be part of your automated build-process, and your Java application will read this information directly from the jar file. All you need is a text file containing the version name (or number). If you’re working with the subversion SCM, you can also easily add the current revision number to the jar file.

The main advantage of this approach is that version information (or any other information, for that matter) is stored in one place, and set at the time the jar file is created. No need for additional configuration files or hardcoded version identifiers in your classfiles.

Here is what you will need:

  1. The build tool Apache Ant.
  2. A Mac, Linux, or other Unix system if you want to add subversion information to the jar file. (Sorry, I’m sure there is way to automatically get the revision information into ant on Windows, but I don’t know how because I don’t use Windows)
  3. A text file containing the version information of your program.

Preparing your build

If you’re using subversion for controlling your repository, you can also add the revision number of the build to the jar-file. To do this, we need a way to access the current revision of your repository.
Create a shell script called getlatestrepoversion.sh containing the following:

#!/bin/bash
echo  `svn info . | grep "Last Changed Rev" | awk '{print $4}'`

and give it execute permission:

chmod u+x getlatestrepoversion.sh

If you don’t use subversion or don’t want that information in your jar-file, just don’t create that shell script, and remove all references to the ant task svn-info from the ant build.xml shown below.

The version number of your project (for example, “1.0″) is stored in a file called build.properties. Create this file, and set an app.version property in it:

app.version=1.0

Ant is controlled by a file called build.xml. By setting “targets”, ant will automatically perform tasks like compiling, creating JavaDocs or bundling up a distribution of your project.

Here is the complete build.xml you need for including build information into your jar file:

<?xml version="1.0"?>

<project name="myProject" basedir=".">
	<description>buildfile for myProject</description>

	<!--
	This initializes the ${DSTAMP} and ${TSTAMP} ant properties.
	-->
	<tstamp/>

	<!-- This file contains informations about the build and is
	loaded automatically -->
	<property file="build.properties"/>

	<!-- set global properties for this build -->
	<property name="src" location="src"/>
	<property name="build"  location="classes"/>
	<property name="jar" location="jar"/>

	<path id="build-classpath">
		<pathelement location="${build}"/>
	</path>

	<patternset id="all-classes">
		<include name="**/*.class"/>
		<exclude name="**/Test/**"/>
	</patternset>

	<target name="init" depends="svn-info">
	<!-- Create the build directory structure used by compile -->
	<mkdir dir="${build}"/>

	</target>

	<target name="svn-info">
		<exec executable="./getlatestrepoversion.sh" outputproperty="svnrevision"/>
		<echo>Repository Version: ${svnrevision}</echo>
	</target>

	<target name="compile" depends="init" description="compile the source " >
		<!-- Compile the java code from ${src} into ${build} -->
		<echo>Compiling ...</echo>
		<javac srcdir="${src}" destdir="${build}" debug="on">
		<classpath refid="build-classpath"/>
		</javac>
		<echo>Done.</echo>
	</target>

	<target name="jar" depends="compile">
		<mkdir dir = "${jar}"/>
		<manifest file="MANIFEST.MF">
			<attribute name="Main-Class" value="your.mainClass"/>
			<attribute name="Class-Path" value="your,class,path"/>
			<!-- This line puts your username into the manifest.
			Maybe you don't want to do that. -->
			<attribute name="Built-By" value="${user.name}"/>
			<attribute name="Built-On" value="${DSTAMP}-${TSTAMP}"/>
			<!-- This property was set by the svn-info task -->
			<attribute name="Revision" value="${svnrevision}"/>
			<!-- This property comes from the build.properties file -->
			<attribute name="Version" value="${app.version}"/>
		</manifest>

		<echo>Building jar file.</echo>
		<jar jarfile="${jar}/${ant.project.name}.jar"
		  			manifest="manifest.mf">
                <fileset dir="${build}/">
                        <patternset refid="all-classes"/>
                </fileset>
        </jar>
	</target>

</project>

I’ve kept everything in it that you need to run the jar-task, so you can easily adopt it to your needs. If you already have a build.xml for your project and only want to add the parts that put the build information into your jar-file, here is what you need to do:

Make sure you call <tstamp/> prior to accessing the timestamp properties and call <property file="build.properties"/> before building the jar.
Call the svn-info task before building the jar (preferable with a “depends” clause) and copy the part about the manifest from the jar target to your own file.

Building the jar file

Before calling ant jar, you need to update your working copy of the repository. Call svn update at the root of your project folder. This will sync the revision number of your working copy with the revison number of the repository. This has to be done even if you just committed a change, because the “global” revision number of the complete working copy will not be updated by a commit.
Note that this will also update any files that have changes in the repository (which is the reason why it is not done automatically).
Then, call ant jar. This will create a jar-file of your project containing the build information.

To verify that all went well, you can either look at the contents of MANIFEST.MF in your current directory, or unpack the created jar-file and check META-INF/MANIFEST.MF.

Accessing the manifest-information in your Java program

By now, the build information is contained in the jar-file and you can find out what version the jar file is used by extracting its contents and looking at the MANIFEST.MF inside the jar. But wouldn’t it be nice if you could access that information programmatically to show the user the version and build information? This little piece of code does exactly that:

public void readManifest()
{
	try
	{
		JarFile jar = new JarFile("./yourJarFile.jar");
		Manifest manifest = jar.getManifest();

		Attributes attribs = manifest.getMainAttributes();

		builtDate = attribs.getValue("Built-On");
		builtBy = attribs.getValue("Built-By");
		version = attribs.getValue("Version");
		revision = attribs.getValue("Revision");

	}
	catch (IOException e)
	{
		log.error("Cannot read jar-file manifest: " + e.getMessage(), e);
	}
}

Two notes on this method: First, it assumes that yourJarFile.jar is in the current working directory (./ on Windows and Unix). On the Mac, this is not the case; the jar-file will be at ./Contents/Resources/Java/yourJarFile.jar.
Second, the method will throw an IOException if the jar file could not be found or not read for any other reason. This will most likely be the case if you launch your program from within an IDE (for example, while working on it). Therefore, we catch the Exception immediately, so your program stays usable even when not started from the jar file.

The variables set are private members of a “Config” class that can be accessed via getters from other parts of the program (for example, an “about” dialog).

8 Responses to “Automatically adding version information into a Java Manifest file with Ant”

Oops… This link will be better: http://java.sun.com/j2se/1.5.0/docs/guide/versioning/spec/versioning2.html#wp90779

It’s a description of the API.

Alexey Filipov, 23.04.2006 @ 13.38

This is one solution if you don’t mind loosing the cross platform nature of Java and Ant by using a bash script ( i.e. getlatestrepoversion.sh ). To get the version information. Why not just use:

${svnversion}

This way you also know if all of the current code is checked in etc.


Whoops your system filtered out my xml. Substitute appropriate angle brackets for parens.

(exec dir=”${basedir}” executable=”svnversion”)
(redirector outputproperty=”svnversion”/)
(/exec)
(echo)${svnversion}(/echo)


Good writing, just what I was hunting for

Danyelle Bruening, 23.04.2006 @ 13.38

So here I was looking for a good article about dahamwirdensalat » Blog Archive » Automatically adding version information into a Java Manifest file with Ant. Searching in Google I managed to find your blog post. After going over this article I’m very glad to say that I most definatelly found exactly what I was searching for. I will make sure to remember site and check it out on a constant basis. Thanks! :-)

forex, 23.04.2006 @ 13.38

I’ve looked at numerous sites and not come across such a web page as yours that tells everyone everything they need to know.

Male Enhancement Product, 23.04.2006 @ 13.38

I’ve looked at numerous sites and not come across such a web page as yours that tells everyone everything they need to know.

male enhancement penis, 23.04.2006 @ 13.38

Leave a Reply