326

I am looking for a way to get a list of all resource names from a given classpath directory, something like a method List<String> getResourceNames (String directoryName).

For example, given a classpath directory x/y/z containing files a.html, b.html, c.html and a subdirectory d, getResourceNames("x/y/z") should return a List<String> containing the following strings:['a.html', 'b.html', 'c.html', 'd'].

It should work both for resources in filesystem and jars.

I know that I can write a quick snippet with Files, JarFiles and URLs, but I do not want to reinvent the wheel. My question is, given existing publicly available libraries, what is the quickest way to implement getResourceNames? Spring and Apache Commons stacks are both feasible.

Marat Salikhov
  • 6,367
  • 4
  • 32
  • 35

16 Answers16

197

Custom Scanner

Implement your own scanner. For example:

(limitations of this solution are mentioned in the comments)

private List<String> getResourceFiles(String path) throws IOException {
    List<String> filenames = new ArrayList<>();

    try (
            InputStream in = getResourceAsStream(path);
            BufferedReader br = new BufferedReader(new InputStreamReader(in))) {
        String resource;

        while ((resource = br.readLine()) != null) {
            filenames.add(resource);
        }
    }

    return filenames;
}

private InputStream getResourceAsStream(String resource) {
    final InputStream in
            = getContextClassLoader().getResourceAsStream(resource);

    return in == null ? getClass().getResourceAsStream(resource) : in;
}

private ClassLoader getContextClassLoader() {
    return Thread.currentThread().getContextClassLoader();
}

Spring Framework

Use PathMatchingResourcePatternResolver from Spring Framework.

Ronmamo Reflections

The other techniques might be slow at runtime for huge CLASSPATH values. A faster solution is to use ronmamo's Reflections API, which precompiles the search at compile time.

Jens Piegsa
  • 7,399
  • 5
  • 58
  • 106
iirekm
  • 8,890
  • 5
  • 36
  • 46
  • Reflections looks like a great idea, but without IDE integration its a bit limiting. – JBCP May 24 '12 at 04:13
  • 13
    if using Reflections, all you actually need: `new Reflections("my.package", new ResourcesScanner()).getResources(pattern)` – zapp Mar 16 '13 at 13:16
  • 40
    Does first solution works when it executed from jar file? For me - it doesn't. I can read file by this way, but can't read directory. – Valentina Chumak Oct 06 '16 at 12:28
  • 3
    In my case I wanted to list non-classfile resources in a path, but only the class files were showing up. So I had to move them to a different directory that doesn't have any classes in the corresponding package. – Jeff Tsay Oct 08 '16 at 20:12
  • The API linked uses Google Reflections but is not a Google project. It is another project on GitHub that happens to use Google libraries. Should the link be changed? – Freiheit Jan 11 '17 at 15:58
  • 6
    The first method described in this answer -- reading the path as a resource, does not seem to work when the resources are in the same JAR as the executable code, at least with OpenJDK 1.8. The failure is rather odd -- a NullPointerException is thrown from deep in the JVM's file processing logic. It's as if the designers didn't really anticipate this use of resources, and there is only a partial implementation. Even if it works on some JDKs or environments, this doesn't seem to be documented behaviour. – Kevin Boone Sep 18 '17 at 07:21
  • 11
    You cant read directory like this, since there is no directory but file streams. This answer is half wrong. – Thomas Decaux Nov 15 '17 at 08:37
  • 4
    The first method doesn't appear to work -- at least when running from the development environment, prior to jarring up the resources. The call to `getResourceAsStream()` with a relative path to a directory leads to a FileInputStream(File), which is defined to throw FileNotFoundException if the file is a directory. – Andy Thomas Dec 06 '17 at 23:14
  • 1
    @ValentinaChumak - How did you read directory when executed from jar? Any solution? – Abhendra Singh May 11 '18 at 03:12
  • `PathMatchingResourcePatternResolver` only seems to return resources in the same Jar as the calling code. Can it also be used to get resources from all the Jars? – tobias_k Apr 17 '19 at 09:49
  • 4
    You really don't want to write your own scanner, if you care about your code working in a wide array of classpath environments, as well as the new JPMS module path. The number of different classpath specification mechanisms is bewildering: https://github.com/classgraph/classgraph/wiki/Classpath-Specification-Mechanisms Instead, consider using ClassGraph, it takes care of all this for you. (I am the author.) – Luke Hutchison Oct 05 '19 at 10:36
  • 3
    It's kind of baffling how highly ranked of a response it is, considering that this will basically not work for any real use case at all. – DoctorPangloss Feb 07 '20 at 21:33
  • Dear @Lena Bru, you're apparently not aware of Java7's try-with-resource and edited the answer to use the traditional try-catch structure, can you tell the reason behind this or can you revert it back please? – KenIchi Sep 23 '20 at 10:55
66

Here is the code
Source: forums.devx.com/showthread.php?t=153784

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;

/**
 * list resources available from the classpath @ *
 */
public class ResourceList{

    /**
     * for all elements of java.class.path get a Collection of resources Pattern
     * pattern = Pattern.compile(".*"); gets all resources
     * 
     * @param pattern
     *            the pattern to match
     * @return the resources in the order they are found
     */
    public static Collection<String> getResources(
        final Pattern pattern){
        final ArrayList<String> retval = new ArrayList<String>();
        final String classPath = System.getProperty("java.class.path", ".");
        final String[] classPathElements = classPath.split(System.getProperty("path.separator"));
        for(final String element : classPathElements){
            retval.addAll(getResources(element, pattern));
        }
        return retval;
    }

    private static Collection<String> getResources(
        final String element,
        final Pattern pattern){
        final ArrayList<String> retval = new ArrayList<String>();
        final File file = new File(element);
        if(file.isDirectory()){
            retval.addAll(getResourcesFromDirectory(file, pattern));
        } else{
            retval.addAll(getResourcesFromJarFile(file, pattern));
        }
        return retval;
    }

    private static Collection<String> getResourcesFromJarFile(
        final File file,
        final Pattern pattern){
        final ArrayList<String> retval = new ArrayList<String>();
        ZipFile zf;
        try{
            zf = new ZipFile(file);
        } catch(final ZipException e){
            throw new Error(e);
        } catch(final IOException e){
            throw new Error(e);
        }
        final Enumeration e = zf.entries();
        while(e.hasMoreElements()){
            final ZipEntry ze = (ZipEntry) e.nextElement();
            final String fileName = ze.getName();
            final boolean accept = pattern.matcher(fileName).matches();
            if(accept){
                retval.add(fileName);
            }
        }
        try{
            zf.close();
        } catch(final IOException e1){
            throw new Error(e1);
        }
        return retval;
    }

    private static Collection<String> getResourcesFromDirectory(
        final File directory,
        final Pattern pattern){
        final ArrayList<String> retval = new ArrayList<String>();
        final File[] fileList = directory.listFiles();
        for(final File file : fileList){
            if(file.isDirectory()){
                retval.addAll(getResourcesFromDirectory(file, pattern));
            } else{
                try{
                    final String fileName = file.getCanonicalPath();
                    final boolean accept = pattern.matcher(fileName).matches();
                    if(accept){
                        retval.add(fileName);
                    }
                } catch(final IOException e){
                    throw new Error(e);
                }
            }
        }
        return retval;
    }

    /**
     * list the resources that match args[0]
     * 
     * @param args
     *            args[0] is the pattern to match, or list all resources if
     *            there are no args
     */
    public static void main(final String[] args){
        Pattern pattern;
        if(args.length < 1){
            pattern = Pattern.compile(".*");
        } else{
            pattern = Pattern.compile(args[0]);
        }
        final Collection<String> list = ResourceList.getResources(pattern);
        for(final String name : list){
            System.out.println(name);
        }
    }
}  

If you are using Spring Have a look at PathMatchingResourcePatternResolver

FoxAlfaBravo
  • 106
  • 1
  • 12
jmj
  • 237,923
  • 42
  • 401
  • 438
  • 3
    Questioner knows how to implement it using standard java classes, but he wants to know how he can utilize existing (Spring, Apache Commons) libraries. – Jeroen Rosenberg Oct 13 '10 at 11:54
  • @Jeroen Rosenberg There is also another way given which has been selected finally :) – jmj Oct 13 '10 at 12:26
  • 10
    I find this solution useful for cases you don't use Spring - it would be ridiculous to add a dependency on Spring becuase of this feature only. So, thank you! "Dirty" but useful :) P.S. One might want to use ``File.pathSeparator`` instead of hard-coded ``:`` in ``getResources`` method. – Tim Sep 27 '11 at 14:05
  • 5
    The code example is system dependent, use this instead: `final String[] classPathElements = classPath.split(System.pathSeparator);` – dcompiled Feb 19 '12 at 20:53
  • Examples can be found here - http://www.programcreek.com/java-api-examples/index.php?api=org.springframework.core.io.support.PathMatchingResourcePatternResolver – Saikat Aug 21 '14 at 11:25
  • 1
    Caveat: The java.class.path system property may not contain the actual classpath you're running under. You could alternatively look at the class loader and interrogate it for what URLs it's loading classes from. The other caveat of course is that if you're doing this under a SecurityManager, the ZipFile constructor can reject your access to the file, so you should be catching that. – Hakanai Feb 08 '16 at 22:59
  • This one is working with desktop app but with webapp "target\classes" is missing. Please help. I posted my problem here : https://stackoverflow.com/questions/48376728/java-code-missing-classpath-from-webapp-but-no-issues-in-desktop-app – Shashank Jan 22 '18 at 08:45
34

Using Reflections

Get everything on the classpath:

Reflections reflections = new Reflections(null, new ResourcesScanner());
Set<String> resourceList = reflections.getResources(x -> true);

Another example - get all files with extension .csv from some.package:

Reflections reflections = new Reflections("some.package", new ResourcesScanner());
Set<String> resourceList = reflections.getResources(Pattern.compile(".*\\.csv"));

Please note: (update)

This answer was written in 2015 and probably used Reflections 0.9.10. Subsequently I've tried the later versions of the Reflections library and struggled getting this answer to work. I also struggled to get examples from their own documentation to work... Personally I'm not sure what the maintainers of the project is doing... Maybe it's an error on my part.

The Reflections project was migrated from the Google Code Archive at version 0.9.9-RC1 as is evident [here]. The project is currently being maintained on github [here].

dutoitns
  • 1,949
  • 1
  • 26
  • 32
  • is there any way to achieve the same without having to import the google dependency? I'd like to avoid to have this dependency just to perform this task. – Enrico Giurin Mar 05 '19 at 22:25
  • 4
    Reflections is not a Google library. – Luke Hutchison Oct 05 '19 at 10:31
  • Maybe it was in the past. My answer is from 2015 and I did find some reference to the library using the phrase "Google Reflections" before 2015. I see the code has moved around a bit and has moved from code.google.com [here](https://code.google.com/archive/p/reflections/) to github [here](https://github.com/ronmamo/reflections) – dutoitns Oct 06 '19 at 18:40
  • @NSduToit that was probably an artifact of hosting the code on Google Code (not an uncommon mistake), not a claim of authorship by Google. – matt b Jan 07 '20 at 19:21
  • it doesn't work. You need to add better examples. It fails with org.reflections.ReflectionsException: Scanner ResourcesScanner was not configured for me. – expert Jun 29 '21 at 14:03
  • @expert This answer was given in 2015 so probably used [Reflections 0.9.10](https://mvnrepository.com/artifact/org.reflections/reflections). The latest version is 0.9.12 - seems a few things has changed because I'm also having problems even running their own examples... I'm also no longer having success with the preceding version in the context of a [Gradle](https://gradle.org/) project... Disappointing. – dutoitns Jul 01 '21 at 19:48
  • how can I figure out which resources come from the "src/test/resources/" directory ? – kommradHomer Feb 02 '22 at 11:28
  • Here is an example of how to do it with the latest version: Reflections reflections = new Reflections(new ConfigurationBuilder().setUrls(ClasspathHelper.forPackage("")).setScanners(Scanners.Resources)); Set resourceList = reflections.getResources(".*"); – Yasser Jun 05 '23 at 22:15
  • @Yasser That only returns resources for me. How does one get the latest Reflections to return all the classes on the classpath? – dutoitns Jun 07 '23 at 15:13
28

So in terms of the PathMatchingResourcePatternResolver this is what is needed in the code:

@Autowired
ResourcePatternResolver resourceResolver;

public void getResources() {
  resourceResolver.getResources("classpath:config/*.xml");
}
Jared Burrows
  • 54,294
  • 25
  • 151
  • 185
Pavel Kotlov
  • 544
  • 4
  • 11
  • 2
    just a small addition if you want to search all possible resources in all the classpath you need to use `classpath*:config/*.xml` – revau.lt Jan 08 '19 at 13:31
24

If you use apache commonsIO you can use for the filesystem (optionally with extension filter):

Collection<File> files = FileUtils.listFiles(new File("directory/"), null, false);

and for resources/classpath:

List<String> files = IOUtils.readLines(MyClass.class.getClassLoader().getResourceAsStream("directory/"), Charsets.UTF_8);

If you don't know if "directoy/" is in the filesystem or in resources you may add a

if (new File("directory/").isDirectory())

or

if (MyClass.class.getClassLoader().getResource("directory/") != null)

before the calls and use both in combination...

Jared Burrows
  • 54,294
  • 25
  • 151
  • 185
Rob
  • 5,353
  • 33
  • 34
  • 4
    Sure, resources may not always be files but the question was about resources originating from files/directories. So use the example code if you want to check different location e.g. if you have a config.xml in your resources for some default configuration and it should be possible to load an external config.xml instead if it exists... – Rob Dec 19 '13 at 16:03
  • 2
    And why resourses are not files? Resourses are files archived into zip archive. Those are loaded into memory and accessed in specific way but I can't see why they are not files. Any exaple of resource that is not 'a file within archive'? – Mike May 18 '17 at 07:20
  • 20
    Not working (NullPointerException) when the target resource is a directory that resides inside a JAR File (i.e. the JAR contains the Main app and the target directory) – Carlitos Way Jun 26 '17 at 23:51
23

The most robust mechanism for listing all resources in the classpath is currently to use this pattern with ClassGraph, because it handles the widest possible array of classpath specification mechanisms, including the new JPMS module system. (I am the author of ClassGraph.)

List<String> resourceNames;
try (ScanResult scanResult = new ClassGraph().acceptPaths("x/y/z").scan()) {
    resourceNames = scanResult.getAllResources().getNames();
}
Luke Hutchison
  • 8,186
  • 2
  • 45
  • 40
  • 3
    Very well done Mr. Hutchison! Perhaps the easiest and most direct way of discovering available resources that I've ever found in Java world. Thank you for an amazing library! – Michael Sims May 11 '22 at 03:29
11

The Spring framework's PathMatchingResourcePatternResolver is really awesome for these things:

private Resource[] getXMLResources() throws IOException
{
    ClassLoader classLoader = MethodHandles.lookup().getClass().getClassLoader();
    PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(classLoader);

    return resolver.getResources("classpath:x/y/z/*.xml");
}

Maven dependency:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>LATEST</version>
</dependency>
BullyWiiPlaza
  • 17,329
  • 10
  • 113
  • 185
9

This should work (if spring is not an option):

public static List<String> getFilenamesForDirnameFromCP(String directoryName) throws URISyntaxException, UnsupportedEncodingException, IOException {
    List<String> filenames = new ArrayList<>();

    URL url = Thread.currentThread().getContextClassLoader().getResource(directoryName);
    if (url != null) {
        if (url.getProtocol().equals("file")) {
            File file = Paths.get(url.toURI()).toFile();
            if (file != null) {
                File[] files = file.listFiles();
                if (files != null) {
                    for (File filename : files) {
                        filenames.add(filename.toString());
                    }
                }
            }
        } else if (url.getProtocol().equals("jar")) {
            String dirname = directoryName + "/";
            String path = url.getPath();
            String jarPath = path.substring(5, path.indexOf("!"));
            try (JarFile jar = new JarFile(URLDecoder.decode(jarPath, StandardCharsets.UTF_8.name()))) {
                Enumeration<JarEntry> entries = jar.entries();
                while (entries.hasMoreElements()) {
                    JarEntry entry = entries.nextElement();
                    String name = entry.getName();
                    if (name.startsWith(dirname) && !dirname.equals(name)) {
                        URL resource = Thread.currentThread().getContextClassLoader().getResource(name);
                        filenames.add(resource.toString());
                    }
                }
            }
        }
    }
    return filenames;
}
Enrico Giurin
  • 2,183
  • 32
  • 30
fl0w
  • 3,593
  • 30
  • 34
6

My way, no Spring, used during a unit test:

URI uri = TestClass.class.getResource("/resources").toURI();
Path myPath = Paths.get(uri);
Stream<Path> walk = Files.walk(myPath, 1);
for (Iterator<Path> it = walk.iterator(); it.hasNext(); ) {
    Path filename = it.next();   
    System.out.println(filename);
}
Jacques Koorts
  • 1,819
  • 1
  • 17
  • 10
  • 6
    doesn't work, when you run a jar: java.nio.file.FileSystemNotFoundException at Paths.get(uri) – error1009 Apr 29 '20 at 08:29
  • I've encountered `FileSystemNotFoundException` before when I wanted to `Paths.get(URI)` a file that was within a Jar. I can't remember the exact details but I guess I got a URI somehow of a resource, but it was actually a resource in a Jar...so visible on the classpath, but on the physical disk it was in a Jar - and Java couldn't load the resource because it considered the Jar as a "file system" it didn't know about it. You can actually create that "file system" using some of the methods in [FileSystem](https://docs.oracle.com/javase/8/docs/api/java/nio/file/FileSystems.html). – dutoitns Jul 08 '23 at 05:37
  • I have all my File manipulation code abstracted away in one class and instead of `Paths.get(URI)` I use the following: [code snippet](https://pastebin.com/dn0K6ftQ). When it tried to `get` one of those resources from a new Jar, it would add the required [FileSystem](https://docs.oracle.com/javase/8/docs/api/java/nio/file/FileSystem.html). – dutoitns Jul 08 '23 at 05:37
4

With Spring it's easy. Be it a file, or folder, or even multiple files, there are chances, you can do it via injection.

This example demonstrates the injection of multiple files located in x/y/z folder.

import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;

@Service
public class StackoverflowService {
    @Value("classpath:x/y/z/*")
    private Resource[] resources;

    public List<String> getResourceNames() {
        return Arrays.stream(resources)
                .map(Resource::getFilename)
                .collect(Collectors.toList());
    }
}

It does work for resources in the filesystem as well as in JARs.

naXa stands with Ukraine
  • 35,493
  • 19
  • 190
  • 259
  • 2
    I want to get the folder names under /BOOT-INF/classes/static/stories. I try your code with @Value("classpath:static/stories/*") and it returns an empty list when running the JAR. It works for resources in the classpath, but not when they are in the JAR. – P-S Feb 27 '19 at 13:00
  • @Value("classpath:x/y/z/*") private Resource[] resources; did the trick to me. Have search hours for that! Thanks! – Rudolf Schmidt Mar 29 '19 at 10:09
3

Used a combination of Rob's response.

final String resourceDir = "resourceDirectory/";
List<String> files = IOUtils.readLines(Thread.currentThread().getClass().getClassLoader().getResourceAsStream(resourceDir), Charsets.UTF_8);

for (String f : files) {
  String data = IOUtils.toString(Thread.currentThread().getClass().getClassLoader().getResourceAsStream(resourceDir + f));
  // ... process data
}
naXa stands with Ukraine
  • 35,493
  • 19
  • 190
  • 259
Trevor
  • 363
  • 7
  • 20
2

I think you can leverage the [Zip File System Provider][1] to achieve this. When using FileSystems.newFileSystem it looks like you can treat the objects in that ZIP as a "regular" file.

In the linked documentation above:

Specify the configuration options for the zip file system in the java.util.Map object passed to the FileSystems.newFileSystem method. See the [Zip File System Properties][2] topic for information about the provider-specific configuration properties for the zip file system.

Once you have an instance of a zip file system, you can invoke the methods of the [java.nio.file.FileSystem][3] and [java.nio.file.Path][4] classes to perform operations such as copying, moving, and renaming files, as well as modifying file attributes.

The documentation for the jdk.zipfs module in [Java 11 states][5]:

The zip file system provider treats a zip or JAR file as a file system and provides the ability to manipulate the contents of the file. The zip file system provider can be created by [FileSystems.newFileSystem][6] if installed.

Here is a contrived example I did using your example resources. Note that a .zip is a .jar, but you could adapt your code to instead use classpath resources:

Setup

cd /tmp
mkdir -p x/y/z
touch x/y/z/{a,b,c}.html
echo 'hello world' > x/y/z/d
zip -r example.zip x

Java

import java.io.IOException;
import java.net.URI;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.util.Collections;
import java.util.stream.Collectors;

public class MkobitZipRead {

  public static void main(String[] args) throws IOException {
    final URI uri = URI.create("jar:file:/tmp/example.zip");
    try (
        final FileSystem zipfs = FileSystems.newFileSystem(uri, Collections.emptyMap());
    ) {
      Files.walk(zipfs.getPath("/")).forEach(path -> System.out.println("Files in zip:" + path));
      System.out.println("-----");
      final String manifest = Files.readAllLines(
          zipfs.getPath("x", "y", "z").resolve("d")
      ).stream().collect(Collectors.joining(System.lineSeparator()));
      System.out.println(manifest);
    }
  }

}

Output

Files in zip:/
Files in zip:/x/
Files in zip:/x/y/
Files in zip:/x/y/z/
Files in zip:/x/y/z/c.html
Files in zip:/x/y/z/b.html
Files in zip:/x/y/z/a.html
Files in zip:/x/y/z/d
-----
hello world
mkobit
  • 43,979
  • 12
  • 156
  • 150
1

path-matching-resource-pattern-resolver

I extracted Spring Framework's PathMatchingResourcePatternResolver into a standalone library for those that can't or don't want to import the whole Spring Framework library.

GitHub

https://github.com/SecretX33/path-matching-resource-pattern-resolver

Add the dependency

Maven

<dependency>
    <groupId>io.github.secretx33</groupId>
    <artifactId>path-matching-resource-pattern-resolver</artifactId>
    <version>0.1</version>
</dependency>

Gradle

implementation 'io.github.secretx33:path-matching-resource-pattern-resolver:0.1'

Gradle (KTS)

implementation("io.github.secretx33:path-matching-resource-pattern-resolver:0.1")

Usage example

Find a single resource

ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource resource = resolver.getResource("classpath:com/example/config.properties");

if (resource.exists()) {
    // Process the resource
}

Find multiple resources

ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource[] resources = resolver.getResources("classpath:com/example/**/*.xml");

for (Resource resource : resources) {
    // Process the resource
}
SecretX
  • 140
  • 1
  • 14
0

Neither of answers worked for me even though I had my resources put in resources folders and followed the above answers. What did make a trick was:

@Value("file:*/**/resources/**/schema/*.json")
private Resource[] resources;
kukis
  • 4,489
  • 6
  • 27
  • 50
0

Expanding on Luke Hutchinsons answer above, using his ClassGraph library, I was able to easily get a list of all files in a Resource folder with almost no effort at all.

Let's say that in your resource folder, you have a folder called MyImages. This is how easy it is to get a URL list of all the files in that folder:

import io.github.classgraph.ClassGraph;
import io.github.classgraph.ResourceList;
import io.github.classgraph.ScanResult;

public static LinkedList<URL> getURLList (String folder) {
    LinkedList<URL> urlList    = new LinkedList<>();
    ScanResult      scanResult = new ClassGraph().enableAllInfo().scan();
    ResourceList    resources  = scanResult.getAllResources();
    for (URL url : resources.getURLs()) {
        if (url.toString().contains(folder)) {
            urlList.addLast(url);
        }
    }
    return urlList;
}

Then you simply do this:

LinkedList<URL> myURLFileList = getURLList("MyImages");

The URLs can then be loaded into streams or use Apache's FileUtils to copy the files somewhere else like this:

String outPath = "/My/Output/Path";
for(URL url : myURLFileList) {
    FileUtils.copyURLToFile(url, new File(outPath, url.getFile()));
}

I think ClassGraph is a pretty slick library for making tasks like this very simple and easy to comprehend.

Michael Sims
  • 2,360
  • 1
  • 16
  • 29
-6

Based on @rob 's information above, I created the implementation which I am releasing to the public domain:

private static List<String> getClasspathEntriesByPath(String path) throws IOException {
    InputStream is = Main.class.getClassLoader().getResourceAsStream(path);

    StringBuilder sb = new StringBuilder();
    while (is.available()>0) {
        byte[] buffer = new byte[1024];
        sb.append(new String(buffer, Charset.defaultCharset()));
    }

    return Arrays
            .asList(sb.toString().split("\n"))          // Convert StringBuilder to individual lines
            .stream()                                   // Stream the list
            .filter(line -> line.trim().length()>0)     // Filter out empty lines
            .collect(Collectors.toList());              // Collect remaining lines into a List again
}

While I would not have expected getResourcesAsStream to work like that on a directory, it really does and it works well.

Deven Phillips
  • 1,129
  • 14
  • 39