Question

I have a problem accessing VFS resources in JBoss using ClassLoader#getResources(-).

I want to list all classpath resources (WEB-INF/classes/*) of some web application (*.war), so I can start with something like:

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

Enumeration<URL> resources = cl.getResources("");

while (resources.hasMoreElements()) {
    Path path = Paths.get(resources.nextElement().toURI());
    InputStream is = Files.newInputStream(path);
}

If I use this code in JBoss AS 7.1 which deploys the application in exploded mode - it works correctly.
As soon as you try to deploy it not in an exploded mode but as an *.war archive it starts throwing the NoSuchFileException.

I assume it's because the non-exploded archive uses virtual filesystem and all such loaded resources starts with `vfs:; in my case it was e.g. vfs:///content/WEB-INF/classes/someResource/.

Therefore the used Path was equal to /content/WEB-INF/classes/someResource and it was treated as a path that doesn't exist (it starts with root-node, slash) and throws an exception.

Just forget for a while about all those cases when the resources was loaded using the HTTP, FTP or others; I'm also not interested in scanning jar's within the classpath. I just want to read all file-based resources on the classpath root.

The problem is I need to enter each resource and find out if this is a folder - if so, list its all elements. That's why the Path element would be very useful here.

The problem is - what is the correct way you should list all resources within your web application?

It seems that resources with vfs: prefix was loaded by some special JBoss classloader, right?

Hence, will I be even able to access the resources in a portable manner (code that will work for JBoss, Glassfish, TomEE, ...)?

EDIT: To give you the context why I need the above: I would like to scan all *.properties files within the classpath and be able to access them with CDI. It has been described here.

Right now I'm switching from old File objects in favour of NIO.2 Paths, Files and basically: input streams.
However, both approaches have the same problem with the vfs:/ resources.

Was it helpful?

Solution

Does the following work?

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

Enumeration<URL> resources = cl.getResources("");

while (resources.hasMoreElements()) {
    InputStream is = resources.nextElement().openStream();
}

OTHER TIPS

Use this dependence

    <dependency>
        <groupId>org.jboss</groupId>
        <artifactId>jboss-vfs</artifactId>
        <version>3.2.15.Final</version>
    </dependency>

Import classs

import org.jboss.vfs.VFS;
import org.jboss.vfs.VirtualFile;
import org.jboss.vfs.VirtualFileFilter;

Method for list all class from WAR

 public void scan(ClassLoader classLoader) throws IOException, URISyntaxException {
    String optionalMainPackage="";
    // Example optionalMainPackage="com.domolin.security"
    Enumeration resources = classLoader.getResources(optionalMainPackage);
    while (resources.hasMoreElements()) {
        URL resource = (URL) resources.nextElement();
        System.out.println("URL "+resource);
        VirtualFile vfDir = VFS.getChild(resource.toURI());
        List<VirtualFile> jsonVFs = vfDir.getChildrenRecursively(new VirtualFileFilter() {
            @Override
            public boolean accepts(VirtualFile file) {
                return (file.isDirectory() || file.getName().endsWith(".class"));
            }
        });
        for (int i = 0; i < jsonVFs.size(); i++) {
            VirtualFile vf = jsonVFs.get(i);
            File f = vf.getPhysicalFile();
            System.out.println("CLASS: "+f.getName());
        }
    }
}

Usage

ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
scan(classLoader);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top