on Jan 7th, 2011Managing development-time dependencies
Over the past few days I’ve seen a number of cases where people are challenged by managing development-time code dependencies. Compiler errors like “<some class> is indirectly referenced from required .class files.” Very annoying.
You can solve this simply by adding a dependency on the package or bundle that contains the missing class(es) but that introduces additional and often unnecessary dependencies and tightly more coupled system.
There is a better way!
First lets step back a second and see what’s going on. Say you have a structure like this…
Here the green lines are the class dependencies (extends). The blue lines are the runtime resolved bundle classloader dependencies (Import-Package or Require-Bundle). At runtime, the C’s classloader simply delegates the loading of its parents to the bundles supplying them. That is, bundle B is asked to load class B. Similarly, bundle B classloader asks bundle A to load the class A. C is doesn’t know anything about A. Great.
Unfortunately, at compile-time the compiler needs to see the entire class structure of C and all its parents. PDE works with JDT to create a compile time classpath that closely mimics that of the runtime but under the covers the compiler uses a flat, non-delegating classloading model that ultimately does not match the runtime. So it ends up with this picture when compiling C. Notice that the red line is effectively the direct dependencies that C is known to have and so does not include a reference to A.
You can see now why adding the explicit dependency in C’s manifest fixes the problem — it adds a red line from C to A but at the expense of additional coupling.
There has to be a way!
Fortunately, you can get the compile-time classpath entry without the bitter aftertaste using PDE’s Automated Management of Dependencies (AMD) mechanism.
The list shown on the Dependencies tab of the bundle manifest editor essentially shows bundles to add to the compile classpath of the bundle. This makes their content available for code completion, searching and compiling but does not change their MANIFEST.MF. Adding bundle A to this list in bundle C solves the compile problem by giving you this without a superfluous dependency. Sweet.
Note that you can have the opposite problem if a bundle is listed in the AMD section but not in the Imports or Requires. In that case, the dependencies are not there at runtime. This problem is easily solved by clicking on the add dependencies link.
AMD has lots of interesting uses as it allows you to basically write your code first and then generate the manifest dependency entries after. Take a few minutes and try it out. I think you’ll like it.