Let’s take as example a project A with its dependencies (including the transitive dependencies). If I look the dependency tree, I see that at the end on one path, I have slf4j-api:1.6.4 and at the end of another path, I have slf4j:1.6.1.
Which dependency I have to choose? If I choose slf4j:1.6.4, I don’t have version 1.6.1 on my classpath, and how can I know if version 1.6.4 will be compatible with the code that uses version 1.6.1?
I don’t understand because at the end I only have one slf4j version on my classpath.
Thanks
This is an old problem known as “Jar Hell”, related to “DLL Hell” in C/C++.
In the case of transitive dependencies you cannot control the versioning and you have no guarantee that differing versions will be compatible. In the simple case of minor version changes in a logger, chances are good that they will be compatible. But, in the general case you will run into conflicts.
OSGi was developed in part to solve this problem. Personally I use the Apache Felix OSGi implementation.
The problem stems from the Java ClassLoader. It cannot load two classes with the same package and class name, meaning it cannot load both versions of slf4j to satisfy your constraints.
OSGi is a Runtime framework that runs on top of the JVM. Rather than running your Jar directly on the JVM using the default classloader, you run your Jar within an OSGi instance.
This requires some addition metadata in your Jar’s manifest file, and these Jars are called Bundles.
OSGi gives each bundle its own ClassLoader, allowing a separation of transitive dependencies. Each of your dependencies would be separate bundles and able to load the version of slf4j within their Bundle’s isolated ClassLoader without naming collisions.