Why is commons-io 2.6 exports 2 versions of same package (1.4. and 2.6.)?

Together with @juergen-albert we were stumbling upon something strange today and I would like to ask, if anybody has an explanation for the following:

  1. go to Maven Central Repository Search
  2. notice the following
<commons.osgi.export>
        <!-- Explicit list of packages from IO 1.4 -->
        org.apache.commons.io;
        org.apache.commons.io.comparator;
        org.apache.commons.io.filefilter;
        org.apache.commons.io.input;
        org.apache.commons.io.output;version=1.4.9999;-noimport:=true,
        <!-- Same list plus * for new packages -->
        org.apache.commons.io;
        org.apache.commons.io.comparator;
        org.apache.commons.io.filefilter;
        org.apache.commons.io.input;
        org.apache.commons.io.output;
        org.apache.commons.io.*;version=${project.version};-noimport:=true
    </commons.osgi.export>
  1. In bndtools in Eclipse this leads to the following output:

These two versions 1.4. and 2.6. gave us some headaches as the 1.4. was showing up in some places, but we were sure that we only had 2.6.0, and were trying to find out where the heck the 1.4. is coming from. Until we found this. Maybe @juergen-albert can explain it a bit better.

My questions is:
Is there a reason behind this?

in gogo you could have done:


inspect cap osgi.wiring.package | grep [org.apache.commons.io](http://org.apache.commons.io)

to find the provider (by id). Then:

inspect cap osgi.wiring.package 31

to see specifics of the bundle(s)

However, to answer your question: Yes! The reason is to support multiple versions of a package from a given bundle. There is no rule that says a bundle must export exactly one version of any package and though it is very, very (, very) uncommon, it is allowed and could be used to solve some rather awkward use cases.

However, I don’t think anyone would recommend doing this in the normal case because it may lead to complex resolution scenarios (exactly what you have encountered.)

  • Ray
1 Like

I don’t know why the maintainers of commons did this. But I suspect it was because they did not do a good job of sematic versioning. And since they export with the project.version, they also need to export with the prior semantic version so that existing code can still resolve against the latest bundle.

OSGi permits a package to be exported multiple times with different attributes to allow for this sort of thing. See https://docs.osgi.org/specification/osgi.core/8.0.0/framework.module.html#framework.module.exportpackage.

Multiple export definitions for the same package are allowed for example, when different attributes are needed for different importers.

1 Like

If this is a permissible pattern, then it appears that equinox (in our case Version 3.15.0) does not like it. It complained that it can not resolve the imports for the 1.4 Version of the commons.io packages. We already looked at it with inspect cap osgi.wiring.package and equinox told that the bundle only exports the packages with the 2.6 Versions.

I have to ask Tom about it. Maybe he knows something.

That’s interesting. I’ve just made a small test, where I only had one bundle that uses commons, gogo running on equinox and it works as expected.

the wiring looks as follows:

org.apache.commons.io_2.6.0 [5] provides:
-----------------------------------------
osgi.wiring.package; org.apache.commons.io 1.4.9999 required by:
   test.simple_2.0.0 [1]
osgi.wiring.package; org.apache.commons.io.comparator 1.4.9999 [UNUSED]
osgi.wiring.package; org.apache.commons.io.filefilter 1.4.9999 [UNUSED]
osgi.wiring.package; org.apache.commons.io.input 1.4.9999 [UNUSED]
osgi.wiring.package; org.apache.commons.io.output 1.4.9999 [UNUSED]
osgi.wiring.package; org.apache.commons.io.monitor 2.6.0 [UNUSED]
osgi.wiring.package; org.apache.commons.io.serialization 2.6.0 [UNUSED]
osgi.wiring.package; org.apache.commons.io 2.6.0 [UNUSED]
osgi.wiring.package; org.apache.commons.io.comparator 2.6.0 [UNUSED]
osgi.wiring.package; org.apache.commons.io.filefilter 2.6.0 [UNUSED]
osgi.wiring.package; org.apache.commons.io.input 2.6.0 [UNUSED]
osgi.wiring.package; org.apache.commons.io.output 2.6.0 [UNUSED]

@chrisrueger I believe you saved the printout we had somewhere in our session. Can you please post it here?

You might want to take a look at snapshot

It creates a snapshot of the framework, among which the package exports and imports. It tries to diagnose potential issues.

It will automatically create a snapshot when the framework is stopped but there is also a gogo command to create an intermediate snapshot. It generates a JSON file that you can drop on: snapshot viewer

Nice feature! Thanks Peter.

@chrisrueger Can you give it a try?

D’oh!
I think I may have found the reason for our trouble:

In our two repositories we have to different commons-io 2.6 jar files.

a. the one from from Maven Central
b. the one from a local repo

I just noticed that they have different meta data.
The a. Maven version specifies both 1.4 and 2.6

But the other one just exports 2.6.

Unfortunately when starting via our bndrun (which contains runbundles org.apache.commons.io;version='[2.6.0,2.6.1)',\ ) the b. local repo version was used which just exports 2.6. … which led to Unresolvable package at startup.

vs.

I am now using only the 2.6 from Maven central, which has both 1.4. and 2.6 (by deleting the other one from the local repo) and everything resolves fine now.

To summarize:

My first suspicion that the two different version are causing issues is not valid. The problem was the other jar which only had the one 2.6 version which caused Unresolvable package problems - but we always inspected the Maven version. So the two different exported versions is actually a good thing in our case.

Now we just need the 2.6 from Maven central and not another additional older 1.4.

I also think the authors did this for backwards compatibility reasons. The lib is pretty simple and probably also backwards compatible with the older 1.4.

Thanks for all the explanations. Always learning a lot here :slight_smile:

Very cool tool :+1: Few questions:

Would you recommond to always add biz.aQute.bnd.runtime.snapshot;version='5.2.0' to runbundles or would you only do this on a case by case basis for debugging?

Is there any documentation besides source?

Is the viewer also on github? Maybe should be linked in the documentation somewhere. What would a good place be? Maybe here?

Ah … WTFM (where is the f*** manual). Well, the beauty of open source ,looking forward to your PR! :nerd_face:

Yes, the viewer is in the bnd runtime project: https://github.com/bndtools/bnd/blob/master/biz.aQute.bnd.runtime/js/index.html

But you can also download it from since the html file contains all the code, there is nno backend behind it: OSGi bnd Snapshot Viewer

Thanks. I will try to write up with something.

@pkriens I have prepared a first draft of an improved snapshot viewer:

Opinions? Is this direction ok? too much?

What is the correct procedure on github? Open issue, then PR?

1 Like

Opinions :slight_smile:

I think the about general info is very nice but should be in their own tab. I am a bit like Google, the front page should be clean. You can open the About tab by default.

I do really like it, and this work is appreciated. You can change the file in bnd/biz.aQute.bnd.runtime/js at master · bndtools/bnd · GitHub and make a PR. I will then copy it to the web site.

Good idea with the separate tab.
PR is here.