How to obtain a package version from the JAR's manifest, using the getImplementationVersion() method of the Package class

11,840

Solution 1

You can read the manifest file from the classLoader and get the value you need as below:

URLClassLoader cl = (URLClassLoader) YOUR_CLASS.class.getClassLoader();
try {
  URL url = cl.findResource("META-INF/MANIFEST.MF");
  Manifest manifest = new Manifest(url.openStream());
  Attributes mainAttributes = manifest.getMainAttributes();
  String implVersion = mainAttributes.getValue("Implementation-Version");

  System.out.println(implVersion);
} catch (IOException E) {
      // handle
}

Solution 2

Solved! At least for me :) You need to make sure, that the package in question is located only in one JAR and that JAR has the correct manifest.

Makes sense, since you query a package for a version and what should the JVM return, if that package is present in many JARs all with different or partially unset implementation versions?

Solution 3

Please make sure you have a newline at the end of the manifest. If there is no newline character at the end, getImplementationVersion() will return null.

Reference : http://docs.oracle.com/javase/7/docs/technotes/guides/jar/jar.html

Solution 4

I had the same issue in eclipse. The problem comes from the Eclipse jar-in-jar class loader. Simply put don't use the package your external libs in the jar method to generate the jar, use the extract external libs into your jar instead method and it should work.

Share:
11,840

Related videos on Youtube

m. vokhm
Author by

m. vokhm

A Java developer

Updated on September 16, 2022

Comments

  • m. vokhm
    m. vokhm about 1 year

    When I prepare my program for deployment, I pack it into a JAR, along with the Eclipse jar-in-jar class loader. When my program runs from the JAR, I need to know a package's version, but I can not obtain it from the jar's manifest a simple and "honest" way. The manifest looks like this:

     Manifest-Version: 1.0
     Created-By: 1.8.0_73-b02 (Oracle Corporation)
     Main-Class: org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader
     Rsrc-Main-Class: com.domain.sp2.controller.Controller
     Rsrc-Class-Path: ./ jar-in-jar-loader.zip javahelp-2.0.05.jar json-simple-1.1.1.jar
     Class-Path: .
    
     Name: com/domain/sp2/controller/
     Implementation-Version: 19
    

    To obtain the package's implementation version, I try to use the simplest and straight-forward way:

    package com.domain.sp2.controller;
    public class Controller {
    ...
       public static String getBuildNumber() throws IOException {
         Package pckg = Controller.class.getPackage();
         pr(pckg.getName());    // prints "com.domain.sp2.controller", as expected 
         return pckg.getImplementationVersion();   // returns null
       }  
    ...
    }
    

    According to http://docs.oracle.com/javase/tutorial/deployment/jar/packageman.html and http://docs.oracle.com/javase/8/docs/api/java/lang/Package.html#getImplementationVersion-- (and other sources), it should return "19", but it returns null. For the packages of the JRE libraries, it returns correct values. Perhaps I have missed a detail about how to name the package in the manifest, or the reason pertains to the JarRsrcLoader - may be it requires some special syntax to address packages. I have also tried ".com/domain/...", "/com/domain/..." and ".../controller", and even "rsrc:./com/domain..." as the package name in the manifest - all without success. I could use other ways, e.g. to load the manifest as stream and parse it with the Manifest class, yet I would like to understand what is the correct way to use the getImplementationVersion() method.

  • m. vokhm
    m. vokhm over 7 years
    Yes, I can read the manifest (as I mentioned in the question), but I would like to know about the getImplementationVersion() method. Why It won't work properly for me? Thank you for the response, nevertheless.
  • m. vokhm
    m. vokhm over 7 years
    Yes, thank you. The manifest is made by Ant, yet I have checked it - the newline is present, even two of them :)
  • m. vokhm
    m. vokhm almost 6 years
    Yet I can't understand what's wrong with my JAR/code. The package is only in one jar (it's a single JAR in my case). Manifest looks OK, at least I see nothing bad there (it's cited in the original post). Nevertheless getName() returns the right name, and the getImplementationVersion() returns null. Java 7 and 8, x32 and x64, Windows.
  • HelloWorld
    HelloWorld almost 5 years
    @m.vokhm regarding why it does not work maybe because the manifest does not have the info you want. If I do Enumeration<URL> resources = MainApp.class.getClassLoader() .getResources("META-INF/MANIFEST.MF"); and loop through the elements I only get Java's official Manifests (I don't know how to name them) like for the first one retrieved : jar:file:/usr/share/java/java-atk-wrapper.jar!/META-INF/MANI‌​FEST.MF . And if I open this manifest, there is no Implementation-Version field. This came to me after looking at the Package private constructor which takes a Manifest.
  • HelloWorld
    HelloWorld almost 5 years
    @m.vokhm Now that I could get I working, I understand better how it works. Did you try getImplementationVersion from IDE or from generated jar ? Because from IDE there is no Manifest (so getImplementationVersion will return null), you'll get it only 'as soon as you launch the real jar'. This jar has a Manifest and depending on how you generated your jar it may contain the version otherwise you'll still get null (but you can add it in this case)