views:

179

answers:

3

From a Java application I can log a string, using a custom logging framework, as follows:

logger.info("Version 1.2 of the application is currently running");

Therefore when a user sends me a log file I can easily see what version of the application they are running.

The problem with the code above is that the version is hardcoded in the string literal and someone needs to remember to update it for every release. It's fairly inevitable that updating this string could be forgotten for a release.

What I would like to do is have this string literal automatically updated based on one of the version numbers in the manifest file for the application's JAR:

Specification-Version: 1.2
Implementation-Version: 1.2.0.0

I don't mind if this happens at compile time or at runtime as long as the version number gets into the log file.

A: 

You can load the manifest at runtime using the following class

public class ManifestFinder {

    private final Class<?> _theClass;


    public ManifestFinder(Class<?> theClass) {

        _theClass = theClass;
    }


    public Manifest findManifest() throws MalformedURLException, IOException {

        String className = _theClass.getSimpleName();
        String classFileName = className + ".class";
        String pathToThisClass = _theClass.getResource(classFileName).toString();

        int mark = pathToThisClass.indexOf("!");
        String pathToManifest = pathToThisClass.toString().substring(0, mark + 1);
        pathToManifest += "/META-INF/MANIFEST.MF";
        return new Manifest(new URL(pathToManifest).openStream());

    }

}

parse the data from the manifest ( untested )

 String specificationVersion = manifest.getMainAttributes().getValue("Implementation-Version");

and then include the parsed version in the log statement

logger.info("Version " + specificationVersion + " of the application is currently running");

See the Jar file specification for more details.

Robert Munteanu
Minor mistake. Missing slash at start of resource name.getClass().getResourceAsStream("/META-INF/MANIFEST.MF");
Iain
Fixed, thank you.
Robert Munteanu
Iain
When multiple JARs are used? How do you know you are getting the version from the right JAR?
ZZ Coder
It all depends on the classloader, but url class loaders in particular fulfill the requirements.
Robert Munteanu
A: 

so you can load your /META-INF/MANIFEST at runtime, using the ClassLoader. Then load and parse Implementation-Version:

String welcome = String.format("Version %s of the application is currently running",
                          implementationVersion);
logger.info(welcome);
dfa
+3  A: 

The standard way to get that information is SomeClass.class.getPackage().getImplementationVersion().

There's no need to do any parsing on your own.

Joachim Sauer
Not sure why but this returns null for me. I've checked the manifest in the generated JAR and it does have the version information. Any ideas?
Iain
Of course "SomeClass" must be loaded from the jar in question.
Joachim Sauer
Can you provide a SSCCE (http://sscce.org/).
Joachim Sauer
I found the problem. The manifest file had a small mistake in the package name. I had 'name: com/company/product' where it should have been 'name: com/company/product/'.
Iain
We set these in the ant script building the jar file.
Thorbjørn Ravn Andersen