Fixing (known) OSGi metadata problems when installing bundle

I am starting to see what people mean about a lot of OSGi metadata being broken! Today I discovered a bundle FOO which depends on both Guava [29, 30) and BAR, where BAR also has an optional dependency on Guava [17, 18). Gradle silently resolves Guava 17 to Guava 29 anyway, and this doesn’t matter until we then add FOO to an OSGi framework and use the particular the package from BAR that triggers its optional Guava dependency. At this point, the framework gives up and throws an exception because no single version of Guava can satisfy both requirements.

Do people routinely rewrite OSGi metadata for 3rd party bundles please? This seems like a terrible burden, and each one requires us to add new dependency substitution rules to our build.gradle scripts too. In this particular case, we’d only need to tweak BAR to require Guava [17, 30) instead of Guava [17, 18). This seems like something we might be able to do when installing bundle BAR instead - perhaps via some kind of BundleListener?

Does OSGi or Bnd have any existing capacity for applying metadata “errata” please? (User-supplied, user specific and hand-written, of course. It would almost certainly need human involvement.)

Thanks for any advice here,
Cheers,
Chris

No, I rarely wrap bundles. However, I have two very well working strategies. First, minimized dependencies. Yes, Guava has some nice classes but since Java 8 you find most of them in the VM already. And if there is this cool feature in a library, I have no qualms copying the source code if the license permits. Since the root problem is transitive dependencies, reducing dependencies in your project tends to have an exponential reduction in overall dependencies, mitigating the problem of bad metadata.

A few years ago I helped someone with some OSGi issues. It turned out that he had 40Mb of dependency JARs to save about 1 line of code. By being very focused on minimizing dependencies, you can reduce most of the problems.

Second, the key for OSGi development is services. Since many open source libraries suck in this respect, I just include these libraries in my own JAR and put an elegant service interface on them. Nobody cares about metadata of the private packages in your bundle. With -conditionalpackage you can even pick out only the parts that you need.

Hi, thanks for replying. The FOO jar is providing some common serializers for general use, some of which are for Guava’s collection types. But when added into an OSGi framework, these serializers can only be used for Guava 17, which isn’t generally useful. And while we could potentially remove Guava types from our own code, we wouldn’t be able to prevent third parties from introducing them again from theirs.

It sounds like we’re going to need to rewrite FOO's Guava version constraint as [17,), which isn’t remotely pretty but would work. But I will examine the OSGi listeners too, to see if we can get the framework to do this programmatically instead.

Cheers,
Chrus

I do not think that model is ever going to work. OSGi is an almost perfect model to build modular applications. and my customers are proving it daily. However, I’ve given up on the idea that it can integrate unmodular applications.

We would be asking third parties to contribute modules written against our API; we don’t want to be unmodular here either. But this doesn’t mean that we can prevent those modules from using Guava internally, and the modules need to be able to serialize/deserialize their own data.

I think we discussed this before? In your application imho the only solution is to force participants to carry their own dependencies in the private bundle area. I do not think sharing can work at that scale and clearly not on your required time frame.

I do not think sharing can work at that scale and clearly not on your required time frame.

I believe we can manage the particular Guava issue I have described above :crossed_fingers:. We obviously do want to isolate our users both from our own internals and from each other as much as possible, if only for the sake of our sanity.

Does this mean that there is no way for an OSGi framework to tweak its bundles’ requirements programmatically, before they can be resolved please? I did consider filtering the InputStream passed to:

BundleContext.installBundle(String, InputStream)

However, that would only work for unsigned bundles :slightly_frowning_face:.

Cheers,
Chris

There is no way in the OSGi framework specification to mutate bundle metadata during install/update. The only way would be to manipulate the InputStream as you noted.

The Eclipse Equinox framework implementation does provide a number of non-standard framework hooks which may be of use here. I am not super familiar with them however.

You might want to take a look at the OSGi Connect specification. This will allow you to do whatever you want.