In this article we address a thorn in the side of OSGi – dynamic class loading. It is one of the most common causes of a
ClassNotFoundException and often inflicted upon you by third-party applications. If you encounter this problem, chin up! All may not be lost. If this is the first time you’ve seen Invoke Ivan’s series on OSGi Demystified, check out his previous blogs here.
- Dynamic Class Loading explained.
- Why Dynamic Class Loading causes problems in OSGi.
1) What is Dynamic Class Loading?
Dynamic Class Loading is the act of programmatically loading classes. An application that loads a class at runtime based on a textual string, can avoid compiling in a dependency on that class. But why would you do that?! Hiding a dependency from the compiler and running the risk of it not being found at runtime – that’s the craft of mad men right? Well yes, and no.
There are distinct advantages to dynamic class loading. Allowing an application to choose which classes to load could help keep it lightweight and relevant. Determining which classes to load can be based on configuration, or perhaps user-input. So let’s say your application needs to connect to a database, and your aim is to support many of the common databases. With JDBC you can abstract away the specific database, but you’ll still need an appropriate JDBC driver. Typically, the user will configure your application for their specific (favourite) database, and your application will need to load the relevant JDBC driver from where the user installed it. By dynamically loading the configured driver you can avoid the overhead of loading all possible drivers, as well as being able to load a driver that you haven’t supplied or installed with your software.
Another example of dynamic class loading is evident in many Java extension mechanisms. Allowing an extender to provide additional function (a plug-in) to your application provides greater flexibility and customisation. A plug-in is typically configured by a text/xml file and then dynamically loaded. As the application developer you won’t know or care what the extenders classes will be called – but using
Class.forName() – the extenders implementation can be located, loaded, and run.
If you play with snakes, expect to be bitten!
As powerful as dynamic class loading is, alarm bells should have been ringing when we said that dependencies are hidden from the compiler. In a normal Java environment as long as the class is somewhere on the single large application class path, you only run the risk of runtime failures if you omit the class from the class path. However, with OSGi and its thou must be explicit approach, your application is much more sensitive to hidden dependencies. There are more boundaries across which you must declare those dependencies and more scope for mistakes because the tooling cannot detect these dependencies. Hidden dependencies in code leads straight to missing dependencies in configuration, which leads straight to ClassNotFoundExceptions!
Do you have a crystal ball?
To visualise the problems caused by dynamic class loading in OSGi, let’s walk through some details. Each OSGi bundle has its own class loader. The bundle’s class path is essentially everything inside the bundle, plus anything on the Bundle-ClassPath, all complimented by any package that is explicitly referenced by the
Import-Package statement in the MANIFEST.MF. Now, if the code in your bundle dynamically loads a class from another package and you don’t know in advance what that package will be (because you can’t predict what will go in the configuration file you are reading) then how do you configure your
Import-Package statement to include it? Without that crystal ball, you can’t.
It is equally confounding if you try to second-guess and declare all the possible packages in advance. By declaring those dependencies, the OSGi framework will insist that they are found AND resolved before your bundle can be started. If they are not present, and by very definition they are dynamically configured and wouldn’t typically be present, your bundle doesn’t get to join the party. The choice of demise is yours.
Want to learn more about dynamic class loading? Be sure to check out the next instalment in the series. Alternatively, take a look at Ivan’s previous post on boot compatibility.