Require-Bundle has an intuitive appeal that is hard to deny. These are the artifacts on the class path during compile time and there is a clear advantage to have these same artifacts during deployment. Import-Package is cumbersome to maintain by hand and basically requires tools like bnd. Besides, the whole world seems to use the Require-Bundle model (maven, ivy, netbeans, ...). So, who would ever want to use Import-Package?
Well, have you ever had chewing gum in your hair?
The harder you try to remove it, the more entangled it gets? This is what Require-Bundle gives you. Import-Package is more like Play-Doh. It is still better not to have it in your hair, but you can ask any kindergarten teacher what she prefers!
So, now we have the right mental image, what is the technical reason for this stickiness? I see two reasons:
- Require-Bundle gives you much more than you actually use because your class files just do not refer to it, a key advantage of a static typed language. Now before you jump to the conclusion you do not care because it is free, realize that there is rent to pay for these unused parts. These unused parts have their own dependencies that need to be satisfied; so they've has just become your dependencies. Visualize the chewing gum in that strand of hair? Dependencies are annoying, and unnecessary dependencies are worse, but these kinds of tied dependencies can be a death knell if they turn out not to be compatible with yours when your code is combined with other bundles to create a system.
- You depend on the whims of the bundle's author. He usually has no clue what parts of his bundle are used and is already busy working on the next version. He will make decisions based on his needs, not yours. It is therefore likely that the constituents in the bundle will change over time. How can you be sure that this migration happens in a way that is compatible with your bundles? Not only can the next version bring quite unnecessary and unexpected new dependencies, it might actually remove the actual packages you depend on. Unfortunately, your bundle resolves because the bundle you require is present, but its changes were just not compatible with your expectations so you get a Class Not Found Exception in the middle of shutting down this nuclear reactor.
The underlying reason for this problem is lack of cohesion. Cohesion is the measure of how much the code in a JAR is related. For example, utility packages or bundles often have quite low cohesion. For example, the Apache Derby SQL database contains a very interesting file system abstraction that is highly usable without Derby. That is, the cohesion between the core SQL database code and this abstraction is very low. The core Derby uses it, but it is not pertinent to being a SQL database. This is common practice because we programmers really dislike to get lots of puny little artifacts.
It is a fact of life that the cohesion in most JARs is quite low while the cohesion in packages is very high. As an example, the Apache Derby file abstraction is nicely packaged in a specification package and an implementation package. Why not extract it one day? Well, I am fine with this improvement and it would not affect any of my bundles at all. Import-Package does not care what bundle provides the package. If I had not warned them so often, I would feel sorry for all my colleagues that just had their bundles broken by a lone programmer somewhere in the world ...
Two very practical use cases that illustrate these problems. Eclipse, who heavily relies on Require-Bundle, needed to support SWT (the graphics library) on the embedded platform and on the SE platform. The embedded platform needed to be a subset of the SE platform. Unfortunately, all users of SWT had been using Require-Bundle. This made the simple solution, refactoring the SWT bundle in two bundles, impossible because it would break each and every Eclipse plugin. Bundles that used Import-Package would have been oblivious of this change.
The other use case is described in a recent blog: Catch-22 Logging with OSGI Frameworks . It is a rather long story but it boils down to that he could not combine two libraries due to unnecessary constraints caused by Require-Bundle with respect to logging. If you have the masochistic desire for the same sensation as having chewing gum in your hair, I recommend to read this blog.