javaclassloadercontextclassloader

Crazy ClassLoader question


The classes:

public interface Inter {
  ...some methods...
}

public class Impl implements Inter {
  ...some implementations...
}

The issue is that for some freaky reason, I have to load the interface Inter with child ClassLoader and the implementation class Impl with parent ClassLoader.

In this case I will get NoClassDefError, because the parent ClassLoader that is trying to load the implementation Impl doesn't know about the interface Inter that was loaded in child ClassLoader.

Is there any way of loading the implementation with child ClassLoader (context ClassLoader) ? Or may be I need to write some custom ClassLoader to load both of them (by breaking the delegation rule) ?


Solution

  • The issue is that for some freaky reason, I have to load the interface Inter with child ClassLoader and the implementation class Impl with parent ClassLoader.

    I cannot fathom why the child classloader must load the interface, while leaving the parent classloader to load the implementation. This is bound to cause trouble, for there is no mechanism within the class-loading mechanism utilized by the JVM, to defer loading of classes to a child classloader. The usual mechanism of implementing the classloading behavior in the JVM is defined in the API documentation of the ClassLoader class:

    The ClassLoader class uses a delegation model to search for classes and resources. Each instance of ClassLoader has an associated parent class loader. When requested to find a class or resource, a ClassLoader instance will delegate the search for the class or resource to its parent class loader before attempting to find the class or resource itself. The virtual machine's built-in class loader, called the "bootstrap class loader", does not itself have a parent but may serve as the parent of a ClassLoader instance.

    One can write a custom classloader, by extending the ClassLoader class and overriding the loadClass() method. Extending this method allows to you to change the class loading delegation in either of the two ways:

    Most classloaders are implemented as parent-first classloaders. This is due to the fact that the delegation mechanism is able to traverse the tree in the upward direction but not in the downward direction.

    If you really wish to delegate loading and finding of classes to child classloaders in the hierarchy, you will have to manage references to them in the custom classloader for the parent. This is not easy, and is usually not done at all except for very exceptional circumstances since it very easy to end up with the dreaded ClassNotFoundException and NoClassDefFoundError as one must be careful to load only the required classes from the child classloaders, while the rest must always be deferred to the parent (unless I'm mistaken, the feature of shared libraries in certain Java EE containers are implemented this way).

    Having said that, the ideal solution would be to attempt loading both the interface and the implementation classes in the parent classloader, and rely on the delegation mechanism to ensure that the classes are visible to both the classloaders; the parent can "see" classes loaded by itself, and the child can "see" the parent's classes.

    PS: Don't forget to use AccessController.doPrivileged when loading and defining classes.