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.

3 Responses to “Managing development-time dependencies”

  1. ekkeon 08 Jan 2011 at 6:41 am

    another great use-case of AMD:

    if there are some bundles exporting same packages and you’re using import package at runtime, then you can help the compiler to choose the right bundle at compile time:
    add the one you want to compile against using AMD – Require-Bundle.

    ekke

  2. Jeremy Dowdallon 08 Jan 2011 at 10:35 am

    Thanks for the tip Jeff, this does indeed come in handy all over the place.

    I’m wondering though, why PDE doesn’t handle this automatically – if it knows what is needed at runtime, why make us go through the extra step to get everything resolved for compile time?

  3. jeffon 08 Jan 2011 at 2:17 pm

    PDE cannot resolve this issue because it is the Java compiler that is actually doing the class loading. At runtime, loading C is done by bundle C’s classloader. While it is loading it notices that B is needed. That delegates to bundle B’s classloader. Similarly, while B is being loaded, A is needed … By contrast, the Java compiler uses one classpath for loading all classes needed when compiling a particular project/class. Theoretically PDE could so some analysis to figure out and find all classes that will be needed during the compilation and put them on a classpath. Seems like that is dipping into the Java model pretty deeply and would be best left to the JDT. There was some discussion on this years ago and there appeared to be some internal design restrictions in JDT that would prevent this dynamic lookup happening efficiently. There was a bug report on it but I can’t find it now.

Comments RSS

Leave a Reply