What You Should Know about Class Loaders

The more (open) source code I see the more I realize that so many developers do not understand the implications of class loaders and just try different things until it seems to work. Not that the Class Loader API is that hard but the implications of Class loaders are often not understood. In a modular environment, class loader code wreaks havoc.

Unfortunately, Class Loaders have become popular as the Java extension mechanism. Developers love the idea that you can take a String and turn it into a Class, there are so many hacks you can do with this! However, what is often not realized that in a modular world this just cannot work. The implicit assumption is that each Class object can be identified with a unique name. It should not take much more than 2 seconds to realize that in a modular world we also require the name of the module because the Class name is no longer unique. That is, class unique.X can actually occur in multiple modules. So given the string “unique.X” there is no way to identify from which module to load this class. In a modular world there are multiple class name spaces!

Multiple Class Spaces

What is the advantage of having multiple class name spaces? Well, it solves a huge problem in larger applications that are built from many parts that come from different sources. Think open source. Take an example of logging. Logging is so popular that everybody does it, unfortunately with different libraries. In practice, it becomes hard to ensure that all your dependencies use the same logging library. In a modular world you can connect each library to its correct logging module. In a non modular world, the first one wins because libraries are placed on a linear search path; you often have no clue who won until you get an error. Obviously this problem is not limited to logging. It is actually kind of flabbergasting that a weak mechanism like the class path is acceptable for professional applications.

So why are developers using strings so often to get a class? Well, the core reason is that Java does not have an extension mechanism. No, the Service Loader is not an extension mechanism, it is encoding of a bad convention leaking its implementation out of all its methods. Extensions through class loading are highly popular, very often in Factory patterns. Sadly, extensions are exactly the place where you want to cross module boundaries. What is the use of an extension that happens to be in your own module? So these strings often contain the name of an implementation class that implements a collaboration interface. The three most important rules of modularity are: Hide, Hide, and Hide. Do you really want to expose the implementation class from a module? Isn’t that the antithesis of modularity?

In spite of these problems, the pattern to use class loaders for extension mechanisms has become highly popular. Today we even have generations that actually do not realize how bad it is to use global variables (class names) to access context through static variables. My programming teacher in 1979 would have set me back a class when I would have proposed such a solution. However, as you know, you go to war with the army you have, not the army you might want or wish to have at a later time. So the class loading hack has become highly popular in lieu of an alternative. So popular that it is used in places where it is not even needed. Worse, it will bite you whenever you move your code base to a modular world.

Guidelines

So here are number of rules/hints you can use to prepare your software for a modular world (and simplify your life at the same time).

Conclusion

The trick to modularity is to make modules that assume as little as possible of the outside world and communicate through well defined interfaces. If you do not know something, you cannot be wrong about it. The pesky factories in Java that use dynamic class loading to get an implementation class just do not fit well in this world. If you’re not ready for OSGi yet but want to prepare your code for the future then following the previous rules will make your code more portable and easier to maintain.

This article was first published on the OSGi Website in 2011.


Comments