views:

719

answers:

4

I know we can do something like this:

Class.class.getResourceAsStream("/com/youcompany/yourapp/module/someresource.conf")

to read the files that are packaged within our jar file.

I have googled it a lot and I am surely not using the proper terms; what I want to do is to list the available resources, something like this:

Class.class.listResources("/com/yourcompany/yourapp")

That should return a list of resources that are inside the package com.yourcompany.yourapp.*

Is that possible? Any ideas on how to do it in case it can't be done as easily as I showed?

Note: I know it is possible to know where your jar is and then open it and inspect its contents to achieve it. But, I can't do it in the environment I am working in now.

A: 

I usually use

getClass().getClassLoader().getResourceAsStream(...)

but I doubt you can list the entries from the classpath, without knowing them a priori.

Vladimir
Can you show please a reference that points what you are saying as a fact ?
David Hofmann
+2  A: 

I've been looking for a way to list the contents of a jar file using the classloaders, but unfortunately this seems to be impossible. Instead what you can do is open the jar as a zip file and get the contents this way. You can use standard (here) ways to read the contents of a jar file and then use the classloader to read the contents.

lewap
+4  A: 

In general can't get a list of resources like this. Some classloaders may not even be able to support this - imagine a classloader which can fetch individual files from a web server, but the web server doesn't have to support listing the contents of a directory. For a jar file you can load the contents of the jar file explicitly, of course.

(This question is similar, btw.)

Jon Skeet
It will be nice to understand why the classloaders don't allow it or why the jre does not provide an easy way to do it :(
David Hofmann
@David: I gave an example of why it's not always feasible - the situation where the only access you have in the underlying store (the web) is "fetch this file".
Jon Skeet
I am sorry, now I got it. It was my bad english and probably lack of attention. Now I understand you. Thanks
David Hofmann
+3  A: 

For resources in a JAR file, something like this works:

URL url = MyClass.class.getResource("MyClass.class");
String scheme = url.getProtocol();
if (!"jar".equals(scheme))
  throw new IllegalArgumentException("Unsupported scheme: " + scheme);
JarURLConnection con = (JarURLConnection) url.openConnection();
JarFile archive = con.getJarFile();
/* Search for the entries you care about. */
Enumeration<JarEntry> entries = archive.entries();
while (entries.hasMoreElements()) {
  JarEntry entry = entries.nextElement();
  if (entry.getName().startsWith("com/y/app/")) {
    ...
  }
}

You can do the same thing with resources "exploded" on the file system, or in many other repositories, but it's not quite as easy. You need specific code for each URL scheme you want to support.

erickson
Thank for the example,Does it use the classloader to reach the resources ?Or it acts like a helper for opening the jar file and inspect its contentes manually ?
David Hofmann
It is a mix of both. It uses the class loader to locate the resource. Then you have to manually list the contents. I didn't show this, but once you have the list of contents, you can return to the class loader for loading if you desire, or load them directly from the archive yourself.
erickson
Hmm, Supose you are in the appengine java vm implementation. It wont allow you to open the file. That was more or less the point. So I think this is the rigth answer, but what I wanted to do is not possible. It may have security concerns implications to not allow it :(Thanks erickson
David Hofmann
Are these jar files you're building yourself? If so, add an extra file (with a fixed name) which contains a list of the other files.
Jon Skeet
Note, JarURLConnection.getJarFile may (and often should) return null. It makes much more sense to do something along the lines of what Jon Skeet says.
Tom Hawtin - tackline
@Jon SkeetThat is exactly what I didn't want to do but it seems that is the only way to achieve it, and is confirmed now :(Thanks !
David Hofmann
erickson