How to read meta data from Manifest file
Asked Answered
T

3

5

I'm trying to extract information from my manifest file to display in one of the methods in my jar file, but seem to be having some issues. Any help is appreciated.

Manifest file:

Manifest-Version: 1.0
Created-By: 1.8.0_60 (Oracle Corporation)
Main-Class: com.example.package1.myClass

Name: com/example/package1
Specification-Title: MyPackage
Specification-Version: v1.1
Specification-Vendor: MyCompanyName
Implementation-Title: MP
Implementation-Version: 2015-11-05-C
Implementation-Vendor: MyName

Name: com/example/package2
Specification-Title: MySecondaryPackage
Specification-Version: v2.0
Specification-Vendor: MyCompanyName
Implementation-Title: M2ndP
Implementation-Version: 2015-11-05-C
Implementation-Vendor: MyName

myClass.java:

package com.example.package1;
import com.example.package2;

class myClass {
  public static void main(String[] args) {
    try {
      myClass clz = new myClass();
      Thread.sleep(10000); //pause 10 seconnds so we can see what's spit out
    } catch (Exception e) {
    //excluded in example
    }
  }

  public myClass() {
    Package pkg = getClass().getPackage();
    if (pkg == null)
      System.out.println("No Package Found");
    else {
      System.out.println("specs: " + pkg.getSpecificationTitle() + " - " + pkg.getSpecificationVersion());
      System.out.println("imps:  " + pkg.getImplementationTitle() + " - " + pkg.getImplementationVersion());
      System.out.println("name:  " + pkg.getName());
    }
    //other code here excluded from example
  }
}

Output:

specs: null - null
imps:  null - null
name:  com.example.package1

So what gives? It looks like the pkg object is being defined correctly, but it doesn't read any of the Specification or Implementation properties.

Tatouay answered 5/11, 2015 at 19:52 Comment(3)
I think this question answers your question: #1273148Syphon
@Clayton, Thanks, but I've already been there and tried that. I've tried several options there but get no further than what I have here; package name, but only null values for the properties.Tatouay
These methods for retrieving properties from a package should work, otherwise what purpose do they serve? Am I just interpreting too much into their function against the manifest.mf file in the jar? I feel like I must be missing something simple. It's driving me nuts.Tatouay
T
4

So I finally figured it out and thought I'd share incase anyone else was banging their head against the proverbial brick wall as much as I was. I never could get the methods in the Package class to return anything other than null. See revised code below for how I managed to pull it off.

package com.example.package1;
import java.util.*;
import java.util.jar.*;
import java.net.*;

class myClass {
  public static void main(String[] args) {
    try {
    new myClass();
    } catch (Exception e) {
    System.out.println(e.getMessage());
    } finally {
    System.out.println("Done");
    try{Thread.sleep(40000);}catch(Exception ee){}
    }
  }

public myClass() throws Exception {
  String clz = getClass().getSimpleName() + ".class";
  String pth = getClass().getResource(clz).toString();
  String mnf = pth.substring(0, pth.lastIndexOf("!") + 1) + "/META-INF/MANIFEST.MF";
  String pkg = getClass().getPackage().getName().replaceAll("\\.","/");
  URL url = new URL(mnf);
  Manifest manifest = new Manifest(url.openStream());

  Attributes attr = manifest.getAttributes(pkg);
  String value = attr.getValue("Specification-Title") + " - " + 
  attr.getValue("Implementation-Title") + " " + 
  attr.getValue("Specification-Version") + " build # " + 
  attr.getValue("Implementation-Version");
  System.out.println(value);
  }
}

Output:

MyPackage - MP v1.1 build # 2015-11-05-C
Done

Which is a lot of code to extract four pieces of Metadata.

So if you like a few less lines here's what I used instead:

public myClass() throws Exception {
  Attributes attr = new Manifest(new URL(getClass().getResource(getClass().getSimpleName() + ".class").toString().substring(0, getClass().getResource(getClass().getSimpleName() + ".class").toString().lastIndexOf("!") + 1) + "/META-INF/MANIFEST.MF").openStream()).getAttributes(getClass().getPackage().getName().replaceAll("\\.","/"));
  String value = attr.getValue("Specification-Title") + " - " + attr.getValue("Implementation-Title") + " " + attr.getValue("Specification-Version") + " build # " + attr.getValue("Implementation-Version");
  System.out.println(value);
}
Tatouay answered 5/11, 2015 at 23:17 Comment(0)
E
2

my approach

public class JarInspector {
    
    public static void printInfo(String[] args){
        if(args.length == 1 && "--info".equals(args[0])){
            try {
                InputStream inputStream = JarInspector.class.getClassLoader().getResource("META-INF/MANIFEST.MF").openStream();
                Manifest manifest = new Manifest(inputStream);
                Attributes attrs = manifest.getMainAttributes();
                if(attrs == null){
                    throw new RuntimeException("no attributes found");
                }
                Set<Object> keys = attrs.keySet();
                for(Object key:keys){
                    System.out.println(String.format("%s: %s", key,attrs.get(key)));
                }
                
            } catch (IOException e) {
                e.printStackTrace();
            }

            java.lang.System.exit(0);
        }
    }
}

public class MyMainApp {
    public static void main(String[] args) {
         //print info jar only if it is called with --info 
         JarInspector.printInfo(args);
    }
}

how to use:

java -c myapp.jar MyMainApp --info
Ed answered 30/3, 2022 at 3:17 Comment(0)
G
1

Add a slash to the end of your package paths. I.e. change com/example/package1 to com/example/package1/. Ask for some class within the package com.example.package1 (we'll call it Foo) and everything should work fine.

Package pkg = com.example.package1.class.getPackage();
String specVer = pkg.getSpecificationVersion();

The trailing slash seems to matter. E.g. here's the manifest from Apache's ant.jar:

Name: org/apache/tools/ant/
Extension-name: org.apache.tools.ant
Specification-Title: Apache Ant
Specification-Version: 1.9.6
Specification-Vendor: Apache Software Foundation
Implementation-Title: org.apache.tools.ant
Implementation-Version: 1.9.6
Implementation-Vendor: Apache Software Foundation
Glume answered 28/7, 2016 at 19:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.