A little problem with the OSGi Version class
| November 4, 2011 | Posted by Karl Beecher under Saros |
With the release of Indigo, Eclipse hackers have been exposed to a little change in the API of the org.osgi.framework.Version class. Specifically, a new method: compareTo(Version) has appeared. Prior to Eclipse 3.7, comparing two Version objects was done via the compareTo(Object) method.
This caused us in the Saros team to suffer a rather subtle bug. When Saros was compiled under Eclipse 3.6 it functioned as expected on the latest version of everyone’s favourite IDE. But when Saros was compiled under 3.7 it suffered an NoSuchMethodException under 3.6 when a call to compareTo() was made. That’s because it was compiled in an environment (Indigo) that inserted a call to compareTo(Version), but was run in an environment (Helios) that knew nothing about such a method.
The reverse situation (compiled in 3.6 and run under 3.7) still worked because a call was inserted that references compareTo(Object). Version inherits from the Comparable interface and thus recognises compareTo(Object) regardless of Eclipse version. I saw at least a couple of other projects complaining online about the same symptoms when I was seeking a solution. As I was unable to find a good solution, I thought I would share with you what I came up with.
To get around the problem, I used reflection. The solution searches first for compareTo(Version) and then for compareTo(Object). Whichever method the code finds, it then executes. Et voilà: code that will run in any iteration of Eclipse regardless of the version it was compiled under… for now at least.
Here’s the gist of the code:
Class versionClass = Version.class; Method compareToMethod = null; try { // Works on Eclipse 3.7 compareToMethod = versionClass.getMethod("compareTo", Version.class); } catch (NoSuchMethodException e1) { log.debug("We're on Eclipse 3.6 or earlier. Fall back compareTo(Object)."); try { // Works on Eclipse 3.6 and earlier compareToMethod = versionClass.getMethod("compareTo", Object.class); } catch (NoSuchMethodException e2) { log.error("Unexpected error: cannot find compareTo() in Version" + e2); } } // Throws InvocationTargetException, IllegalAccessException compareToMethod.invoke(v1, v2);
Isn’t it possible to import a strict version in the MANIFEST.MF for the org.osgi.framework package?
This seems like a dependency management problem on your part. You compiled against version 1.6 of the framework package, yet you don’t seem to import the framework package at version 1.6 (that is “[1.6,2.0)”).
If you really want your code to run on a 1.5 framework, compile your code against the 1.5 framework package.
What you describe above is just a hack to deal with one observed problem caused by your dependency management problem.
I thought about this, but it didn’t strike me as a good solution. It’s not that we just want to run against OSGI 1.5, we want to run against ANY version of OSGI.
By blanket insisting on a specific version I would think that leaves us open to the risk of incompatibilities in every place we reference OSGI. Isn’t it better to fix the known causes as they are found than introduce such a risk?