Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Need a Java system-only class loader

I would like to find or create a Java class loader that loads only system classes, excluding any classes on the application defined class path. My goal is to use that class loader to build a class loader that loads from a specific JAR file, resolving system classes using the system-only class loader, but not contaminating the classes from the JAR file with any classes defined by my application.

So far I have not found any way to create a system-only class loader that does not either use private APIs or make assumptions about the Java implementation. See code below that works in my current environment but makes undesirable assumptions.

If there is no way to create an implementation independent system-only class loader, is there a reason why not? Is what I am trying to do a bad idea?

private ClassLoader createJarClassLoader(File f)
{
    ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
    if (systemClassLoader instanceof URLClassLoader) {
        URLClassLoader cl = (URLClassLoader) systemClassLoader;
        URL[] urls = cl.getURLs();
        List<URL> wantedURLs = new ArrayList<>();
        for (URL u : urls) {
            if (isSystemURL(u)) {
                wantedURLs.add(u);
            }
        }
        try {
            wantedURLs.add(f.toURI().toURL());
        } catch (MalformedURLException ex) {
            return null;
        }
        return new URLClassLoader(wantedURLs.toArray(new URL[0]), null);
    }
    return null;
}

private boolean isSystemURL(URL u)
{
    return u.getPath().contains("/jre/");
}
like image 709
Alan Snyder Avatar asked Dec 05 '15 04:12

Alan Snyder


1 Answers

You need to set the parent ClassLoader to be the bootstrap ClassLoader. Call getClassLoader() on a java.lang.String object to get the bootstrap ClassLoader and use that in your ClassLoader constructor.

public class MyClassLoader extends URLClassLoader {

    protected MyClassLoader(URL[] urls, ClassLoader parent) {
        super(urls, parent);
    }

    static MyClassLoader getInstance(URL[] urls) {
        ClassLoader parent = "".getClass().getClassLoader();
        return (new MyClassLoader(urls, parent));
    }
}

The representation of the bootstrap classloader is documented as implementation dependent

Some implementations may use null to represent the bootstrap class loader. This method [getClassLoader] will return null in such implementations if this class was loaded by the bootstrap class loader.

but the same wording applies to parent ClassLoader in the ClassLoader constructor, which means that this solution is portable.

like image 117
Neil Masson Avatar answered Oct 14 '22 11:10

Neil Masson