An early believer in the ability of Java to deliver "enterprise-grade" software, Andrew Phillips quickly focused on the development of high-throughput, resilient and scalable J2EE applications. Specializing in concurrency and high performance development, Andrew gained substantial experience of the intricacies, complexity and challenges of enterprise application environments while working for a succession of multinationals. Continuously focused on effectively integrating promising new developments in the Java space into corporate software development, Andrew joined XebiaLabs in March 2009, where he is a member of the development team of their deployment automation product Deployit. Amongst others, he also contributes to Multiverse, an open-source Java STM implementation, and jclouds, a leading Java cloud library. Andrew is a DZone MVB and is not an employee of DZone and has posted 22 posts at DZone. You can read more from them at their website. View Full User Profile

Making the Bootstrap Loader "just another ClassLoader"

02.25.2011
| 4294 views |
  • submit to reddit

Recently, I was tweaking MultiSPI to add the following class loading fallback logic:

if (threadContextLoader != null) {
loadFromContextLoader(className);
} else if (systemLoader != null) {
loadFromSystemLoader(className);
} else {
loadFromBootstrapLoader(className);
}

and realized that it's not immediately evident how to do this in a uniform way. But actually, it's quite simple...getting a ClassLoader object for the bootstrap loader is just a couple of lines of code.

So what's the problem?

Well, if you're happy with a literal implementation of the pseudo-code above, there obviously isn't a problem.

ClassLoader loader = Thread.currentThread().getContextClassLoader();
if (loader != null) {
return loader.loadClass(className);
}

loader = ClassLoader.getSystemClassLoader();
if (loader != null) {
return loader.loadClass(className);
}

// null is the bootstrap loader
return Class.forName(className, true, null);

But this is very procedural code, and it would already be much more OO if we could do something like:

getLoader().loadClass(className);

ClassLoader getLoader() {
ClassLoader loader = Thread.currentThread().getContextClassLoader();
if (loader != null) {
return loader;
}

loader = ClassLoader.getSystemClassLoader();
if (loader != null) {
return loader;
}

return ...???????
}

The problem is that there simply isn't a ClassLoader.getBootstrapClassLoader() or equivalent method. You can try to walk up the system loader's parent hierarchy, of course, but what you're likely to find is that the bootstrap loader will be represented by null - not very useful in our circumstances.

Writing BootstrapClassLoader

So what we want is to come up with a ClassLoader implementation that delegates straight to the bootstrap loader. One option would be to override loadClass to simply call Class.forName with the above arguments, but there's actually an even easier way:

class BootstrapClassLoader extends ClassLoader {
BootstrapClassLoader() {
/*
* The default classloader implementation will use the bootstrap loader
* if it finds a null parent.
*/
super(null);
}
}

Now we can finish our getLoader method:

// or simply "new ClassLoader(null) {};"
final ClassLoader BOOTSTRAP_LOADER = new BootstrapClassLoader();

ClassLoader getLoader() {
ClassLoader loader = Thread.currentThread().getContextClassLoader();
if (loader != null) {
return loader;
}

loader = ClassLoader.getSystemClassLoader();
if (loader != null) {
return loader;
}

return BOOTSTRAP_LOADER;
}

Unless we're being really performance-conscious, we can even turn this into the almost functional:

ClassLoader getLoader() {
return Iterables.find(asList(Thread.currentThread().getContextClassLoader(),
ClassLoader.getSystemClassLoader(), BOOTSTRAP_LOADER), Predicates.notNull());
}

There's a demo snippet on PasteBin here.

From http://blog.xebia.com/2011/02/24/making-the-bootstrap-loader-just-another-classloader/

Published at DZone with permission of Andrew Phillips, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Tags: