views:

763

answers:

4

Hi All,

This is a common problem. I'm using 2 libraries A.jar and B.jar and these depend on different versions of the same jar.
Let's say that at runtime I need THIS.x.x.x.jar

MY.jar   
     -> A.jar -> THIS.1.0.0.jar
     -> B.jar -> C.jar -> THIS.5.0.0.jar

I can compile the specific jar (A.jar/B.jar) against its dependency but at runtime I've to load only 1 version. Which one?
Loading only 1 dependency (the latest version) means that my code will probably throw runtime exceptions if the libraries are not Backward Compatible (are there Backward Compatible libraries out there?).

Anyway I know that something like OSGi can fix this issue.
I'm wondering what's the old way to fix this kind of problems...

Thanks a lot

+1  A: 

Many libraries are backward compatible. But not all..


The old way is to try to depend from only one version.

It is probably safer to compile both with the same version (latest).
At least you get compile-time errors, instead of runtime errors.

If needed, you can modify a little bit your library that works with the old dependency...
This would require access to the source...


Please note that compile-time compatibility will not guarantee correct runtime behavior either. It is one step, then you can:

  • read the WhatsNew file for the new version of the jar
  • look on the Internet for users reporting compatibility problems
  • write JUnits
  • compare the codes in both jars
KLE
+3  A: 

OSGi can fix this problem. An OSGi bundle is nothing more than a jar with additional metadata detailing versions. A bundle has a version number, and will detail version numbers (or ranges) of dependent jars.

Take a look at this introductory Javaworld article for more information.

To solve this without OSGi means having to ensure manually that you compile and run with compatible jars. As you've discovered that's not necessarily a trivial task. Since jars don't necessarily identify their versions, the only sure way to do this to record/compare checksums or signatures.

Brian Agnew
+1  A: 

As mentioned by KLE, the default approach is to depend on the newer version. There is no guarantee, but most of the time this works. Probably the best way (while being a bloated one) is using OSGI to get over it.

sfussenegger
+1  A: 

"Old way" you mentioned (and the one OSGI certainly uses under the hood) is to install your own ClassLoader for both branches of your dependencies. That's how, for instance, application servers are able to run both older and newer versions of the same application inside the same JVM.

Read about classloader hierarchy.

In your setup, the tricky part is the joint point, where classes from both branches meet. Neither branches can use classes loaded into another one. The way to make it work is to make sure only classes loaded by boot classloader (JRE classes) or classloader of MY.jar are passed down to both branches.

Vladimir Dyuzhev