6

I want to list all files with a specific name in the class path. I am expecting multiple occurrences, hence Class.getResource(String) will not work.

Basically I have to identify all files with a specific name (ex: xyz.properties) anywhere in the class path and then read the metadata in them cumulatively.

I want something of the effect Collection<URL> Class.getResources(String) but could not find anything similar.

PS: I don't have the luxury of using any third party libraries, hence in need of a home grown solution.

Shama
  • 178
  • 2
  • 9
  • 3
    this similar question can help you http://stackoverflow.com/questions/6730580/how-to-read-several-resource-files-with-the-same-name-from-different-jars – logoff Oct 09 '12 at 13:25

3 Answers3

5

You can use Enumeration getResources(String name) on the class loader to achieve the same.

For example:

Enumeration<URL> enumer = Thread.currentThread().getContextClassLoader().getResources("/Path/To/xyz.properties");
while (enumer.hasMoreElements()) {
    System.out.print(enumer.nextElement());
}
Ashwin Prabhu
  • 9,285
  • 5
  • 49
  • 82
  • Can you give an example how the OP should be using that. He wants to find all resources that match a pattern in the classpath. Just giving a link is IMO not sufficient as an answer. – maba Oct 09 '12 at 13:39
  • `ClassLoader#findResources()` is `protected`. – maba Oct 09 '12 at 13:45
  • @maba Thanks, I stay corrected. Guess I wasn't paying close attention to the API docs. BTW usage is pretty straightforward, but anyways I will edit my answer with a usage. – Ashwin Prabhu Oct 11 '12 at 11:17
2

What I do is I read java source files from classpath and process them using ClassLoader. I am using follwing code :

ClassLoader classLoader = Thread.currentThread().getContextClassLoader();

assert (classLoader != null);

// pkgName = "com.comp.pkg"
String path = pkgName.replace('.', '/');

// resources will contain all java files and sub-packages
Enumeration<URL> resources = classLoader.getResources(path);

 if(resources.hasMoreElements()) {
        URL resource = resources.nextElement();     
        File directory = new File(resource.getFile());
        // .. process file, check this directory for properties files
 }

Hope this helps you.

Nandkumar Tekale
  • 16,024
  • 8
  • 58
  • 85
1

The existing answers that propose using ClassLoader.getResources(String) only work if the "name" in question is the full path of the resource. As the methods's javadoc states, "The name of a resource is a /-separated path name that identifies the resource." It's unfortunate and misleading that the parameter is called "name" instead of "path."

For those who, like me, are really looking for all resources with a given (simple) name - without knowing the full path of the resource - the current answers won't work. @NandkumarTekale's code example states "resources will contain all java files and sub-packages" in the comments, but unfortunately that is not true. Nor does it make any difference to use ClassLoader.findResources(String) (which is indeed protected in the ClassLoader class itself, but pulled into the public API by concrete subclasses like URLClassLoader, which in turn serves as the base class for most commonly used class loaders).

The most straightforward solution that I could find uses the ClassGraph library:

try (ScanResult result = new ClassGraph().acceptClasspathElementsContainingResourcePath("*/html5.dtd").scan())
{
    System.err.println(result.getResourcesWithLeafName("html5.dtd").getURLs());
}

Sadly, this clashes with the OP's request for a solution without the use of third-party libraries. However, ClassGraph's source code is available on GitHub and can be used as an inspiration for a "home grown" solution. In broad strokes, one would have to find the class loader's base URLs (e.g., using URLClassLoader.getURLs()) and then write URL-specific code for searching the contents of each URL (e.g., if it's a jar:file:... URL, load the JAR and iterate over its contents, or if it's a file:... URL use java.io.File to explore the folder contents). There are a lot of special cases to consider, though (e.g., OSGi class loaders), and a truly general solution would probably replicate a fair amount of what ClassGraph does under the hood. If it is valid to assume that the resources will, for example, always be packaged in a JAR (or always as plain files in the file system), a more tailored solution could be created for just those cases.

raner
  • 1,175
  • 1
  • 11
  • 21