How to get a resource in another jar

2020-03-26 04:50发布

I have a jar embedded in a bundle that needs to fetch a resource packaged with it like so:

MyBundle
  -\ src
  -\lib
    -\MyEmbeddedJar
      -\src
        -\SomeClass
      -\someResource.xml

I am trying to access 'someResource.xml' from 'SomeClass' like so:

SomeClass.class.getResource( "someResource.xml" ); 

But I've had no luck. I've tried several variations with the CWD appended (eg: './someResource.xml') but I just can't get this resource to load.

I know that the "right" way is to use Activator to get hooks back to the proper classloader, but the embedded jar can be used in other projects, so I'd hate to have to add OSGi specific code to it just to get it to play nice with OSGi.

Is there any other way to load resources in OSGi agnostically of OSGi?

4条回答
Juvenile、少年°
2楼-- · 2020-03-26 04:58

My assumptions are that:

  1. That I'm not quite sure I get how your description of the problem matches the diagram. Where is the *.jar file?
  2. The bundle that is attempting to access the embedded jar is the same bundle that contains the embedded jar.
  3. Per the OSGi agnosticism, I am assuming that the embedded jar is not explicitly exposed as part of the current bundle's classpath and that it is not loaded as another OSGi bundle.

If the jar in question is itself a resource of the current classloader, then you would first need to get the jar as a resource or as an InputStream, such as with MyBundleClass.class.getResourceAsStream("/pathToJar.jar"); then wrap it with a java.util.jar.JarInputStream. Then, continue to call getNextJarEntry() until you find the JarEntry object where "someResource.xml".equals(jarEntry.getName()).

查看更多
够拽才男人
3楼-- · 2020-03-26 05:03

I'm going to make the following assumption:

embedded.jar
    src/SomeClass.class
    someResource.xml

and the bundle contains embedded.jar and embedded.jar is on the Bundle-Classpath.

In this situation SomeClass.class.getResource("someResource.xml") will look for a resource on the classpath called src/someResource.xml because SomeClass is in the package src. In order to get someResource.xml in the root of the jar you need to do SomeClass.class.getResource("/someResource.xml") instead.

This isn't OSGi specific though, this is just how resource loading works in Java.

查看更多
时光不老,我们不散
4楼-- · 2020-03-26 05:05

I Assume that SomeClass is inside the embedded jar (say, somejar.jar), and someResource.xml is in the outer jar, in a lib directory.

In this case, there is no way to get to that in a non-OSGi context. Let's look at both situations in isolation.

In OSGi

Your someResource.xml should very well be reachable using the regular (non-OSGi specific) resource loading mechanisms, provided that it is reachable from the Bundle-ClassPath. For instance, if you have the following manifest header,

Bundle-ClassPath: ., somejar.jar

you will be able to get to your resource using "lib/someResource.xml". Notice the dot on the classpath: this means you can reach classes and resources from the root of the jar. If you forget that, you will only be able to get to classes and resources inside somejar.jar.

Not using OSGi

If you're not using OSGi, there is no (reasonably simple) way to get to classes and resources inside of the inner jar that I know of.

Your options

Depending on what you want your bundle to look like, you have two options now.

  1. Is it really necessary that SomeClass is in an embedded jar? If so, you're at a loss, and you jar will only work using OSGi.
  2. If you have the option to 'unpack' somejar.jar into your jar, you subvert the problem, and your jar can work in both situations.

Personally, I'd pick option 2.: unless you have resources that might overwrite each other when you 'merge' the jars, it is no problem at all to have a slight mess of resources inside your bundle.

查看更多
爷、活的狠高调
5楼-- · 2020-03-26 05:15

I'm going to accept @Angelo's solution as it gave me the idea on how to work around this, though, I'd like to add more information in - thus my answer.

My work around was to add another constructor to SomeClass that takes in a java.net.URL instance. I also copied someResource.xml into the bundle's root.

I then updated the instantiation of SomeClass in the bundle like so:

new SomeClass( FileLocator.find( Activator.getDefault().getBundle(), new Path( "./someResource.xml" ), new HashMap< String, String >() ) );

This seems like a pretty big hack to me. What if I could not edit the contents of SomeClass ? I guess I would have to unpack it or I'd be forced to wrap it into it's own bundle?

查看更多
登录 后发表回答