Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/bjhargrave/loadertest

Class.forName caches defined class in the initiating class loader
https://github.com/bjhargrave/loadertest

Last synced: 27 days ago
JSON representation

Class.forName caches defined class in the initiating class loader

Awesome Lists containing this project

README

        

[Class.forName caches defined class in the initiating class loader](http://blog.bjhargrave.com/2007/09/classforname-caches-defined-class-in.html)
=================================================================

In my [previous entry](http://blog.bjhargrave.com/2007/07/why-do-classforname-and.html), I wrote about how how there is a difference in behavior between `Class.forName` and `ClassLoader.loadClass`. Since then I wrote a simple (for class loaders :-) test case to demonstrate the difference.

When calling `ClassLoader.loadClass` to load a class, the initiating class loader delegates to another class loader which actually defines the class. The defined class is only added to the defining class loader's cache. The cache of the initiating class loader's cache is not altered. So if the initiating class loader delegates to a different defining class loader on a future request for the class, the class is always returned from the defining class loader to which the delegation occurred. This is of course how the [ContextFinder](http://wiki.eclipse.org/index.php/Context_Class_Loader_Enhancements) from Eclipse is intended to work. ContextFinder is the initiating class loader which uses context from the call stack to select the *right* bundle class loader to delegate the actual class load request.

However, if `Class.forName` is used to call the initiating class loader, the behavior with respect to caching and the returned class is quite different. In this case, when the class is first defined, it is cached by the defining class loader as expected. But it is also cached by the initiating class loader which is *not* expected. Even more unusual and unexpected is that `Class.forName`, through its native implementation, seems to consult the initiating class loader's cache *directly* before calling `loadClass` on the initiating class loader which is the normal place where the class loader's cache is consulted (via `ClassLoader.findLoadedClass`). As a result, all calls to `Class.forName` to a initiating class loader always return the same class object (the first one loaded), even if the implementation of the initiating class loader does not define classes or directly consult its own cache.

The test case also showed that `ClassLoader.loadClass` always works as expected even when interleaved with calls to `Class.forName`.

If every one always used `ClassLoader.loadClass` to consult the Thread Context Class Loader (TCCL), then a ContextFinder style TCCL choice would work very well in OSGi (or any similar module system) . However a lot of code uses `Class.forName` to consult the TCCL which means that a ContextFinder style TCCL is not going to help those callers.

The test case also includes a test to see whether having `Class.forName` add the class object to the initiating class loader's cache would result in pinning the class in the heap after the class and its defining class loader became garbage collected. This would also be a problem for OSGi since it would cause a ContextFinder style TCCL (which would have a lifetime of the framework) to potentially pin a bundle's class loader and all loaded classes in the heap. Fortunately, this was not an issue. The class object was removed from the initiating class loader's cache once the class and its defining class loader were garbage collected. So, interestingly enough, the reference to the class from the initiating class loader's cache must be a sort of weak reference which allows the class to be garbage collected.

This unexpected behavior of `Class.forName does` not seem to be documented or explained anywhere that I have located. If you know of any such documentation, please let me know! In any case, there is a problem in designing a useful TCCL solution for OSGi.