Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting the path to the directory of a given class file

I was confronted with code which tries to read some configuration files from the same directory where the .class file for the class itself is:

File[] configFiles = new File(
    this.getClass().getResource(".").getPath()).listFiles(new FilenameFilter() {
        public boolean accept(File dir, String name) {
            return name.endsWith(".xml");
        }
});

Apparently this works in some cases (when running the code inside Resin, perhaps), but for me, running Tomcat, it simply fails with NPE, because getClass().getResource(".") returns null.

A colleague suggested creating another config file containing a list of all the ".xml" config files (which indeed would work here as it stays quite static), and that you shouldn't really try to do something like this in Java.

Still, I'm wondering if there is some nice way, which works universally, for getting the path to the directory where a given .class file is located? I guess you could get it from the path of the .class file itself like this:

new File(this.getClass().getResource("MyClass.class").getPath()).getParent()

... but is this the only / cleanest way?

Edit: To clarify, assume we know this is used in an application deployed in such a way that MyClass.class will always be read from a .class file on disk, and the resources will be there in that same directory.

like image 487
Jonik Avatar asked Sep 05 '25 09:09

Jonik


1 Answers

I know this thread is old, but it's the top result in Google searches, and there were no satisfactory answers on here, for me. Here's some code I wrote, which works great for me. Of course there's the caveat that it may not have been loaded from disk, but it accounts for that, and returns null in that case. This works fine for finding the "container," that is, the root location of a class, be it a jar, or a folder. This may not suit your needs directly. If not, feel free to rip out the portions of the code that you do need.

/**
 * Returns the container url for this class. This varies based on whether or
 * not the class files are in a zip/jar or not, so this method standardizes
 * that. The method may return null, if the class is a dynamically generated
 * class (perhaps with asm, or a proxy class)
 *
 * @param c The class to find the container for
 * @return
 */
public static String GetClassContainer(Class c) {
    if (c == null) {
        throw new NullPointerException("The Class passed to this method may not be null");
    }
    try {
        while(c.isMemberClass() || c.isAnonymousClass()){
            c = c.getEnclosingClass(); //Get the actual enclosing file
        }
        if (c.getProtectionDomain().getCodeSource() == null) {
            //This is a proxy or other dynamically generated class, and has no physical container,
            //so just return null.
            return null;
        }
        String packageRoot;
        try {
            //This is the full path to THIS file, but we need to get the package root.
            String thisClass = c.getResource(c.getSimpleName() + ".class").toString();
            packageRoot = StringUtils.replaceLast(thisClass, Pattern.quote(c.getName().replaceAll("\\.", "/") + ".class"), "");
            if(packageRoot.endsWith("!/")){
                packageRoot = StringUtils.replaceLast(packageRoot, "!/", "");
            }
        } catch (Exception e) {
            //Hmm, ok, try this then
            packageRoot = c.getProtectionDomain().getCodeSource().getLocation().toString();
        }
        packageRoot = URLDecoder.decode(packageRoot, "UTF-8");
        return packageRoot;
    } catch (Exception e) {
        throw new RuntimeException("While interrogating " + c.getName() + ", an unexpected exception was thrown.", e);
    }
}
like image 199
LadyCailin Avatar answered Sep 08 '25 22:09

LadyCailin