9

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
  • 669
  • 1
  • 6
  • 24
  • This has an answer [here](http://stackoverflow.com/questions/33553570/how-to-read-meta-data-from-manifest-file) already – SomeDude Jul 05 '16 at 13:08
  • Yes, I'm sure. I see it in the JAR win an open eye, in the right place (.META-INF/), and I can read it (including the Implementaion-Version) programmatically. I just don't want to load the manifest and parse it, when the getImplementationVersion() exists. – m. vokhm Jul 05 '16 at 13:09
  • @svasa, this is not an answer for my question. I did not ask how to read the manifest. My question is "how to use the the getImplementationVersion() method". I should have expressed the question more clearly. I'll edit it. – m. vokhm Jul 05 '16 at 13:24

5 Answers5

6

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
}
Radouane ROUFID
  • 10,595
  • 9
  • 42
  • 80
  • 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 Jul 05 '16 at 13:19
  • @m.vokhm regarding why it does not work maybe because the manifest does not have the info you want. If I do `Enumeration 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/MANIFEST.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 Nov 25 '18 at 03:35
  • 1
    @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) – HelloWorld Nov 25 '18 at 04:52
6

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?

Tom
  • 1,965
  • 3
  • 25
  • 33
  • 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. – m. vokhm Nov 25 '17 at 09:22
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

  • Yes, thank you. The manifest is made by Ant, yet I have checked it - the newline is present, even two of them :) – m. vokhm Jul 05 '16 at 13:28
1

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.

Guenadi
  • 11
  • 1
0

I found this issue in my IDE (Eclipse) because the run from within the IDE wasn't using the generated Manifest in the jar. To see the correct behavior, I just went to the command line of the computer to run the jar (since I had an appropriate main class set). But put another way, even if it doesn't work within the IDE, it should work in deployment.

ktbos
  • 450
  • 4
  • 5