How to allow a deeper version of jar-hell?

I have two Java projects Test1 and Test2. Test1 has a lib library added to it in the Eclipse Java Build Path. Test2 has an added jar in its build path.

Test1 Test2 /src /src lib Referenced Libraries x-1.1.jar a.jar y.jar x-1.2 z 

The code in Test1 calls the functions / classes of y.jar, which is dependent on x-1.1.jar. I do not know what functions / classes x-1.1.jar are used by y.jar, since I do not have a source for cans. Similarly, Test2 calls the functions / classes of the package z a.jar, which are dependent on x-1.2 verion jar.

Now I have a test project where I need both projects Test1 and Test2

 Test /src Test1 code Test2 code some other code which uses Test1 as well as Test2 libraries lib x-1.1.jar y.jar Referenced Libraries a.jar x-1.2 z 

Now when I start the Test project, I get into the jar-hell situation. My research uses two approaches:

  • Class path: The problem with this approach is that since the / jar library for Test1, Test2 is added to the Java eclipse build path, only the first downloaded version of x.jar is available, and Test2 code breaks even when using the class loader.
  • osgi: the problem with the approach is that I can only export packages to the src folder Test1 and Test2 from the osgi package, and not the one referenced by the project. But there is code in the test project that uses the Test1 and Test2 libraries.

I hope I'm clear enough. Any help is appreciated. Thanks in advance.

Adding additional information to the question: I have to use two different java-sdks in my project that are associated with different jar files. Conflicting are:

 jar file Test1 ver Test2 ver org.apache.commons.codecs 1.3 1.6 org.apache.commons.logging 1.1.1 1.1.1 org.apache.log4j 1.2.7 1.2.15 httpclient 4.1.1 4.0.3 httpcore 4.1 4.1.4 

What are some possible ways to do this?

+4
source share
2 answers

OSGI is actually most likely a solution, and you have two ways to do this:

  • Converting dependent jars to osgi packages, determine which version of packages they export (just use real version numbers) link (OSGI path) from your test projects, when importing packages, specify the exact required versions. This way you will create an osgi package for each jar library and for each of your projects.
  • Create two osgi packages: test1 and test2. Insert their desired version of libraries (like built-in banks or built-in) and do not export dependent packages. You can freely reference test1 and test2 from the test package. They will not collide, but will be in isolated class loaders (bundle classloader space). Information on how to embed dependencies using the maven bundle plugin: http://felix.apache.org/site/apache-felix-maven-bundle-plugin-bnd.html#ApacheFelixMavenBundlePlugin%28BND%29-EmbedDependencyandExportPackage

Emphasis on this configuration:

 <Embed-Dependency> *;scope=compile|runtime;inline=false </Embed-Dependency> 

How to wrap jars in osgi using the BND tool: http://java.dzone.com/articles/how-creategenerate-osgi

By the way, most (if not all) of your mentioned libs should already be osgi ready, so you don’t even need to convert them to osgi packages. The only problem that may arise here is that some banks are not compatible with osgi (for example, those that make assumptions about the architecture of the container class loader), but this is a quiet rare case.

+1
source

You can try to emulate classpath separation, as OSGi does, by implementing a custom class loading mechanism with two URLClassLoader s, one for each of x-1.*.jar s.

This is a general idea:

 File x1jar = new File("path/to/x-1.1.jar"); URLClassLoader x1loader = new URLClassLoader (x1ar.toURL(), this.getClass().getClassLoader()); File x2jar = new File("path/to/x-1.2.jar"); URLClassLoader x2loader = new URLClassLoader (x2ar.toURL(), this.getClass().getClassLoader()); // Test1 should look into x-1.1.jar .. Class test1class = Class.forName("Test1", true, x1loader); // .. Test2 should look into x-1.2.jar .. Class test2class = Class.forName("Test2", true, x2loader); // .. but both should see y.jar and z.jar via system class locader. // Invoke whatever methods in testXclasses. 

IMPORTANT: x-1.1.jar and x-1.2.jar should not be on the way to the system, i.e. you should put them in a separate lib folder, i.e. deploying your class should look like this:

 + myapp + lib myapp.jar y.jar z.jar + sandbox x-1.1.jar x-1.2.jar 

And you should not relate directly to the class Test1 / Test2 (using Test1 or Test1.class ), only with class names (in the line "Test1" ).

Check out this answer and this one .

0
source

All Articles