David Williams
David Williams

Reputation: 8654

How to Get List of Classpath Resources In Nested Jar?

I have a Maven project, and I am packaging it as a single fat jar using the One-Jar Maven plugin. According to this page on the One-Jar site documentation resource loading must be done in a special manner with One-Jar packaged apps, however that documentation does not cover how to list the resources in a manner which does not depend on their custom class loader.

My question is this: how to I list the contents of the root of my classpath within an inner jar in a packaging agnostic manner, meaning not assuming it will always be in such special packaging? As covered in this SO question, Spring's PathMatchingResourcePatternResolver will not work because Spring's DefaultResourceLoader ignores the classloader.

NOTE: The closest SO question I could find was this question, but this does not address the listing of classpath resources from nested jars.

Upvotes: 0

Views: 1512

Answers (2)

Mark Melville
Mark Melville

Reputation: 813

It can be done in a FAT jar. Your own answer stating it's not possible has a link to a page that shows it's possible! It's not that insane of a solution. Here's a slightly modified version:

private List<String> getResourceFiles(String path) throws IOException
{
    List<String> files = new ArrayList<>();
    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    URL dirURL = classLoader.getResource(path);
    if (dirURL.getProtocol().equals("jar"))
    {
        String jarPath = dirURL.getPath().substring(5, dirURL.getPath().indexOf("!"));
        try (final JarFile jar = new JarFile(URLDecoder.decode(jarPath, "UTF-8")))
        {
            Enumeration<JarEntry> entries = jar.entries();
            while (entries.hasMoreElements())
            {
                String name = entries.nextElement().getName();
                if (name.startsWith(path + "/") && !name.endsWith("/"))
                {
                    files.add(name);
                }
            }
        }
        return files;
    }

    // return some other way when not a JAR
}

This version will return the full resource path of any file under the given resource path, recursively. For example, an input of config/rest would return files under that resource folder as:

config/rest/options.properties
config/rest/samples/data.json

With those values, one can get the resource with ClassLoader::getResource, or get the contents of the resource with ClassLoader::getResourceAsStream.

Upvotes: 1

David Williams
David Williams

Reputation: 8654

After reviewing many articles, and blogs posts, web pages, site and the Spring source code, I had concluded this is just a weakness in Java and is not possible in any sane manner.

Upvotes: 0

Related Questions