badge

Every Java package (JAR, WAR, EAR, etc.) has a MANIFEST.MF file in the META-INF directory. The file contains a list of attributes, which describe this particular package. For example:

Manifest-Version: 1.0
Created-By: 1.7.0_06 (Oracle Corporation)
Main-Class: MyPackage.MyClass

When your application has multiple JAR dependencies, you have multiple MANIFEST.MF files in your class path. All of them have the same location: META-INF/MANIFEST.MF. Very often it is necessary to go through all of them in runtime and find the attribute by its name.

jcabi-manifests makes it possible with a one-liner:

import com.jcabi.manifests.Manifests;
String created = Manifests.read("Created-By");

Let's see why you would want to read attributes from manifest files, and how it works on a low level.

Package Versioning

When you package a library or even a web application, it is a good practice to add an attribute to its MANIFEST.MF with the package version name and build number. In Maven, maven-jar-plugin can help you (almost the same configuration for maven-war-plugin):

<plugin>
  <artifactId>maven-jar-plugin</artifactId>
  <configuration>
    <archive>
      <manifestEntries>
        <Foo-Version>${project.version}</Foo-Version>
        <Foo-Hash>${buildNumber}</Foo-Hash>
      </manifestEntries>
    </archive>
  </configuration>
</plugin>

buildnumber-maven-plugin will help you to get ${buildNumber} from Git, SVN or Mercurial:

<plugin>
  <groupId>org.codehaus.mojo</groupId>
  <artifactId>buildnumber-maven-plugin</artifactId>
  <executions>
    <execution>
      <goals>
        <goal>create</goal>
      </goals>
    </execution>
  </executions>
</plugin>

After all these manipulations, MANIFEST.MF, in your JAR will contain these two extra lines (on top of all others added there by Maven by default):

Foo-Version: 1.0-SNAPSHOT
Foo-Hash: 7ef4ac3

In runtime, you can show these values to the user to help him understand which version of the product he is working with at any given moment.

Look at stateful.co, for example. At the bottom of its front page, you see the version number and Git hash. They are retrieved from MANIFEST.MF of the deployed WAR package, on every page click.

Credentials

Although this may be considered as a bad practice (see Continuous Delivery: Reliable Software Releases through Build, Test, and Deployment Automation by Jez Humble and David Farley), sometimes it is convenient to package production credentials right into the JAR/WAR archive during the continuous integration/delivery cycle.

For example, you can encode your PostgreSQL connection details right into MANIFEST.MF:

<plugin>
  <artifactId>maven-war-plugin</artifactId>
  <configuration>
    <archive>
      <manifestEntries>
        <Pgsql>jdbc:postgresql://${pg.host}:${pg.port}/${pg.db}</Pgsql>
      </manifestEntries>
    </archive>
  </configuration>
</plugin>

Afterwards, you can retrieve them in runtime using jcabi-manifests:

String url = Manifests.read("Pgsql");

If you know of any other useful purposes for MANIFEST.MF, let me know :)