ClassLoader FAQ

Please consider this a work in progress. I will update it as warranted.

First review the concepts and considerations outlined in the Java Language Specification on Execution.

The issue of package security restrictions, and the definition of 'instanceof' require that each instance of a given class must be created from the same Class object. Any deviation will cause package security issues as well as 'instanceof' to return false, when it should otherwise be considered true.

Classes in the same package but loaded from different class loaders cause a new Error("try to access class "+classname_a+"\n from class "+classname_b) to be thrown. Therefore the class loader set for each class is very important. The way that the 1.2 ClassLoader model avoids this issue is by having all subclasses delegate class loading to the system class loader. Because all classes thus loaded have the same class loader, the above test passes. This explains why the problem is currently, under 1.2, asymptomatic.

If two instances of the same class have different class loaders, they are not considered within the Java language as the same class. That is, instanceof, fails, because hashCode() returns a memory location, and because they have a different memory location, a1.getClass().hashCode()!=a2.getClass().hashCode(), when the only issue is that the current 1.2 model for ClassLoader does not follow the JLS specification and consider reloading already loaded classes erroneous.

Now consider the following:

Let us assume ClassLoader class_loader_A, has loaded classes from package ax.ay.
Let us further assume that code loaded by class_loader_A, instantiates (ClassLoader)class_loader_B with a different URL list, and a parent Class Loader of class_loader_A.

According to Sun's model, class_loader_B loads classes/packages from its URL list. If a class needs to be loaded that it cannot load, then it delegates the loading of said class to its parent class loader.

What if a given class x could be loaded by both class_loader_A and class_loader_B?

In this case, per Sun's model, both class_loader_A and class_loader_B would load the same class, and since they would have different hashCode() values, as discussed above, then a class comparison or instanceof test will fail.

Note: this problem only occurs if you have more than one class loader. Sun's model assumes only one class loader, and that any subclass will defer any actual class loading to the system class loader. Thereby avoiding these issues. The current 1.2 model uses this solution to avoid solving the problem.

Before we go on, what is it that a class loader must do? If one has read the JLS section referred to above, it has been made very clear, that once a class is loaded, the same Class object must be returned regardless of the ClassLoader object used to load said class. If this is not done, nothing works.

If you have more than one class loader, then you must guarantee the above for all cases. The 1.2 design and implementation of java.lang.ClassLoader overtly prevents this possibility. The methods that would otherwise be used to perform this functionality are private.

To further complicate the situation, java.lang.ClassLoader can only forward UP the class loader chain those classes that cannot be loaded, without any facility for child class loaders, and testing whether or not a class has already been loaded. That a ClassLoader can load a class, does not mean that it should load a class.

What if class loader class_loader_B above, has loaded classes in a package, that loader class_loader_A also can load? In order to always return the same class once it is loaded, then every class loader must know both its parent as well as child class loaders, so that once loaded, the same class is always equal to itself, regardless of which classes and/or class loaders are used.

Ok, assuming the above is understood, there is another issue entirely.

Calling the method defineClass(), causes the loadClass() method in the current class to be called again for any classes that need to be resolved. Once all referenced classes in a given class are also loaded, then the associated class object is returned. This is why the tentativePackages object exists. If a given package is a new reference, and loader class_loader_B (as above) is calling defineClass on it, and it is possible that classes to be loaded by another class loader also reference this same package, then you have a problem if you use Sun's model. If on the other hand, you track which packages are being currently loaded, and resolved, then you can relegate the loading of classes to those loaders that have already loaded, or are CURRENTLY LOADING, classes in this package. This is not a trivial point.

Since the initial version of this FAQ, I have added 'static public HashTable package_to_classLoader' to make package class loader resolution faster and easier. It makes attempting to find the appropriate ClassLoader for a given package much simpler. Only when a class and its package are unknown is the loading delegated down then up the ClassLoader chain. The assumption that the common case will be when there is no child class loader, and that if there is a child, then from "here" to the bottom of the chain should be attempted first. This is assuming that when a child class loader is added to the chain, that subsequent class loading activity will be most active in the new child, and not still in one of its ancestors.

Please keep in mind that what is implemented in java.lang.ClassLoader is not meant to be consistent with the Java Language Specification, nor intended to allow for the functionality the JLS dictates as required for a functional (or subclass of) ClassLoader.

Ken Graham.