How to read manifest.mf from POJO class (not a servlet) instantiated by spring?
Asked Answered
W

3

3

I have a simple service called BuildNumberService which would be instantiated by spring.

I'm trying to find the cleanest code for the class to find out the MANIFEST.MF file from the jar file it has been packaged into.

The code has to run inside a servlet container.

@Service
public class BuildNumberService {

    private static final String IMPLEMENTATION_BUILD = "Implementation-Build";

    private String version = null;

    public BuildNumberService() {

      // find correct manifest.mf
      // ?????


      // then read IMPLEMENTATION_BUILD attributes and caches it.
       Attributes mainAttributes = mf.getMainAttributes();
       version = mainAttributes.getValue(IMPLEMENTATION_BUILD);
    }

    public String getVersion() {
        return this.version;
    }
}

How would you do that ?

Edit: Actually, what I'm trying to do, is, find a resource by name which sits in the same package as the actual class.

Withindoors answered 11/10, 2010 at 15:43 Comment(2)
I guess you can see the answer to that question.Retrospect
take a look at jcabi-manifests with a utility class that does all this work for youIty
U
2

Well if you know the jar is on the file system (e.g. not inside a war) and you also know that the security manager gives you the permission to access a class' protection domain, you can do it like this:

public static InputStream findManifest(final Class<?> clazz) throws IOException,
    URISyntaxException{
    final URL jarUrl =
        clazz.getProtectionDomain().getCodeSource().getLocation();
    final JarFile jf = new JarFile(new File(jarUrl.toURI()));
    final ZipEntry entry = jf.getEntry("META-INF/MANIFEST.MF");
    return entry == null ? null : jf.getInputStream(entry);
}
Unchartered answered 11/10, 2010 at 15:58 Comment(4)
Psshh.. JarFile#getManifest().Syndrome
@Syndrome that would be too easy. Let me do the leg work myself :-) (To be honest, didn't know about that)Unchartered
Is that the only way for a class to find the jar in which it is packaged ? It seems that the jdk makes it difficult to read these metadata at runtime. As if it was not supposed to be done.Withindoors
not supposed to be done. I'd rephrase that to: only supposed to be done by folks who really know what they are doing (e.g. frameworks that have component scanning like hibernate, spring, seam etc. must use functionality like this). But yes, I'd guess it's the only wayUnchartered
B
3

I've found another solution to load MANIFEST.MF without referencing servlet context, by just using Spring Framework.

I used this configuration with Spring 3.1.2.RELEASE, but I believe it should work fine on later releases.

First, write the following bean in your applicationContext.xml

<bean class="java.util.jar.Manifest" id="manifest">
    <constructor-arg>
        <value>/META-INF/MANIFEST.MF</value>
    </constructor-arg>  
</bean>

You should notice that the constructor argument from Manifest class accepts an InputStream as a parameter, however, you don't need to worry about that 'cause Spring converts the provided value to match constructor arguments. Moreover, by starting the path with a slash / (/META-INF/...), Spring looks for this file on a servlet context object whereas starting with classpath: prefix it steers Spring to look over the classpath to find the requested resource.

Second, declare the aforementioned bean in your class:

@Autowired
@Qualifier("manifest")
private Manifest manifest;

My MANIFEST.MF is under the folder $WEBAPP_ROOT/META-INF/ and I've successfully tested this solution on Apache Tomcat 7 and WildFly 8.

Baltazar answered 6/9, 2014 at 13:47 Comment(0)
U
2

Well if you know the jar is on the file system (e.g. not inside a war) and you also know that the security manager gives you the permission to access a class' protection domain, you can do it like this:

public static InputStream findManifest(final Class<?> clazz) throws IOException,
    URISyntaxException{
    final URL jarUrl =
        clazz.getProtectionDomain().getCodeSource().getLocation();
    final JarFile jf = new JarFile(new File(jarUrl.toURI()));
    final ZipEntry entry = jf.getEntry("META-INF/MANIFEST.MF");
    return entry == null ? null : jf.getInputStream(entry);
}
Unchartered answered 11/10, 2010 at 15:58 Comment(4)
Psshh.. JarFile#getManifest().Syndrome
@Syndrome that would be too easy. Let me do the leg work myself :-) (To be honest, didn't know about that)Unchartered
Is that the only way for a class to find the jar in which it is packaged ? It seems that the jdk makes it difficult to read these metadata at runtime. As if it was not supposed to be done.Withindoors
not supposed to be done. I'd rephrase that to: only supposed to be done by folks who really know what they are doing (e.g. frameworks that have component scanning like hibernate, spring, seam etc. must use functionality like this). But yes, I'd guess it's the only wayUnchartered
T
0
Manifest mf = new Manifest();
Resource resource = new ClassPathResource("META-INF/MANIFEST.MF");
                    InputStream is= resource.getInputStream();
                        mf.read(is);
                        if (mf != null) {
                            Attributes atts = mf.getMainAttributes();
                            implementationTitle = atts.getValue("Implementation-Title");
                        }
Thibeault answered 1/5, 2019 at 18:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.