Wednesday, November 20, 2013

Conflicting classes in multiple dependent jars

Working in Teradata, I discovered an issue related to multiple versions of Spring dependent jars. The problem is that we use Ivy to add project jar dependence. Each jar/project can have different versions of Spring jars in its library. For a master project which depends on several other base projects and having its own Ivy library, as a whole, its library will have different version of Spring jar files. These jars can contain same class with different contents. Some earlier versions might not have the implementation for certain methods added later. This problem is mostly applicable in Eclipse when all the library files are loaded in CLASSPATH, including the library files for dependent projects. A standalone jar invocation can avoid this issue by providing a precise Manifest file containing only needed jars!

One error I got when running the project in Eclipse is as below:

Invalid property 'maxConcurrentConsumers' of bean class [org.springframework.jms.listener.DefaultMessageListenerContainer]

Notice due to the usage of Spring injection, the above error is not discovered at compilation time. In the example DefaultMessageListenerContainer.setMaxConcurrentConsumers is provided in Spring 2.0.6 but not in Spring 2.0. Other issues are also found including Spring's support for Circular references.

I found it is hard to remove the dependence of the old versions of Spring jars from dependent projects. Even using "transitive = 'false'" tag on the Ivy configuration does not work. I have to live with multiple versions of jars containing the same class. To make sure using the latest version of the jar, I have to depend on the JVM class loader order. Fortunately I found this is doable within eclipse. Eclipse's JVM will load the jars in the order of your specification in the "Java Build Path" --> "Order and Export". As long as the correct version of the jar (or ivy.xml) is before the obsolete jar (or dependent project), the issue can be avoided.