Finding closure in your Imports

I really dislike bundles that have a myriad of implementation dependencies. Dependencies that are only used by one bundle and pollute the public package space in OSGi. A perfect bundle depends on services specified in a Java package that has few no dependencies. We see this model becoming prevalent outside the Java world. On Apple’s, nowadays you need to bring your own Java VM and the average Android applications are tens of megabytes. Sharing dependencies turns out to be so hard that we’d prefer to make things much larger to not share.

To make my perfect bundles (pun intended) I tend to include my dependencies. From the start, bnd has had the possibility to ‘borrow’ Java byte-codes from other bundles. If you did an Export-Package or Private-Package instruction, then the source is the class path, not just the code in your project. This tend to result in duplicate code but since OSGi can handle this very well as long as it is private code, you only get bigger bundles; a price well worth paying at today’s memory & bandwidth cost.

The remaining problem therefore was to find the exact closure of packages that would make my unwanted import list empty. Finding out this set was tedious. Since I’ve been doing software since the late seventies, I recalled that we could statically link applications. After the application was assembled, the linker looked in a library and added any dependencies it could find from the archive. The tricky part was that those modules brought in their own dependencies, so this process was recursively applied until there were no more missing links.

I therefore added the -conditionalpackage instruction. As usual in bnd, you can specify one or more glob patterns to match the package names you want to recursively include.

 -conditionalpackage  aQute.lib*

The library used in the example, aQute.libg, was specifically developed for this type of inclusion. There are, however, many JARs that are not as cleanly designed. Although bnd tries to include the whole package, sometimes there are resource dependencies bnd is unaware of. Also the evil hack Class.forName() can throw bnd off.

And one last reminder, this only works well in OSGi since we have true modules where the same code can be present multiple times as private packages.

1 Like