Search code examples
javaclassloader

How to put custom ClassLoader to use?


Hello all and thanks for the attention! I have a problem that must both be easy and obvious, yet I am stuck.

I want to deliver dynamically created Java classes to be used by a 3rd party library via a custom ClassLoader.

Now my problem is: How do I set my custom ClassLoader to be used to load this classes when I do not load them directly myself?

I thought when I used my ClassLoader to load a certain class, it became this class's ClassLoader, and all classes loaded from that class would be channeled through my ClassLoader.

I created a custom ClassLoader, following this official tutorial: http://java.sun.com/developer/onlineTraining/Security/Fundamentals/magercises/ClassLoader/help.html.

public class DynamicClassloader extends ClassLoader {

    private Map<String, Class<?>> classesMap = new HashMap<String, Class<?>>();

    public DynamicClassloader(ClassLoader parent) {
        // Also tried super(parent);
        super(sun.misc.Launcher.getLauncher().getClassLoader());
    }

    // Adding dynamically created classes
    public void defineClass(String name, Class<?> clazz) {
        classesMap.put(name, clazz);
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        // load from parent
        Class<?> result = findLoadedClass(name);
        if (result != null) {
            return result;
        }
        try {
            result = findSystemClass(name);
        } catch (Exception e) {
            // Ignore these
        }
        if (result != null) {
            return result;
        }
        result = classesMap.get(name);
        if (result == null) {
            throw new ClassNotFoundException(name);
        }
        return result;
    }
}

I wanted to use this somewhere else in the code like that:

ClassLoader thisClassLoader = this.getClass().getClassLoader();
((DynamicClassloader) thisClassLoader).defineClass(className, dynClass);

Now my problem is that when I call findSystemClass(name) of the 3rd party library class, the parent ClassLoader finds this class (because it is on the classpath) and becomes its ClassLoader. And since the parent ClassLoader doesn't know about my custom ClassLoader, it is effectively been put out of use and this.getClass().getClassLoader() cannot be cast to DynamicClassLoader.

Another approach would be to set my ClassLoader to be the system ClassLoader via JVM argument -Djava.system.class.loader=my.DynamicClassloader. But that gives me a StackOverflowError:

    ...
at de.unisaarland.cs.st.DynamicClassloader.findClass(DynamicClassloader.java:39)
at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
at java.lang.ClassLoader.findSystemClass(ClassLoader.java:916)
at de.unisaarland.cs.st.DynamicClassloader.findClass(DynamicClassloader.java:39)
    ...

This must be really easy to do, yet I am now out of ideas... any help is greatly appreciated!


Solution

  • Not sure I understand the question, you have a 3rd party lib and you want it to use your classloader to load classes.

    If you're lucky the third party lib uses the threads context classloader which you can set using Thread.currentThread().setContextClassLoader(myClassLoader), in the same thread you can access this classloader with Thread.currentThread().getContextClassLoader()...

    Another point, but not sure it is important in your context, is that you can also write a parent-last classloader that will try to load the class before delegating to its parent (instead of trying to delegate first)

    Edited after your comment:

    parent_last classloader will make a difference if your library doesn't rely on the thread context classloader, then you have to load the library with your parent-last classloader thus setting your classloader as the classloader for the library instead of its parent loader (the parent of your classloader)...

    You may also make a classloader with a parent-first behavior but for your 3rd party library...

    And a good link about classloaders...