Using Eclipse 3.4.2, I found a couple of nasty bugs involving package dependencies. Let's say I have the following situation:
- two plug-ins plugin.a and plugin.b
- plugin.a exports the package a.ui and has a non-exported package a.model
- a public class, a.ui.Ui, has a method with the signature a.model.Model getModel()
In plugin.b, there is some code that looks like this:
a.ui.UI ui = ...; if (ui.getModel().hasSomeProperty()) ...
The Eclipse compiler accepts this code. It should not, since ui.getModel() returns an object of type a.model.Model, and the a.model package is not exported from the plug-in. In fact, if I rewrite this code like this...
a.ui.Ui ui = ...; a.model.Model model = ui.getModel(); // error flagged here if (model.hasSomeProperty()) ...
... then Eclipse will complain about the second line, saying that a.model.Model is not visible. It will offer a quick fix to export the a.model package from the plug-in.
Okay, so the compiler doesn't catch this. Big deal! You'll find out about your problem when the OSGI run-time tries to load the a.model.Model class, right? Wrong! OSGI will sometimes catch the error, and sometimes not. Specifically, if the class a.model.Model is loaded for the very first time by code that exhibits this error, then OSGI will correctly identify that an access rule has been broken. But if the class has already been loaded, then OSGI does not perform access checking at all. Once a class is loaded, then that class can be accessed by any bundle that depends upon the containing bundle -- whether or not the containing package is exported. So much for OSGI security!
This combination of bugs has an insidious effect to which I fell victim. In my case, the code was "broken" but it "worked" because the affected class had already been loaded long before the code was invoked. I made an apparently minor change to the affected class and suddenly a mysterious ClassNotFoundException appeared at runtime (the change had subtly altered the class-loading order).
I'm more worried about situations where the class-loading order is sensitive to actions taken by the user. If the user performs actions in one order, everything works. If the user tries a different order, then ClassNotFoundException. I suppose this occurrence is rare enough that we don't have to concern ourselves about it (famous last words).
Another argument in favour of the Law of Demeter ;)