When we work with projects which use Java, the first thing that we do is add dependencies, libraries or frameworks, that we need to use. To do this, we use a dependency management tool like Maven or Gradle, depending on the benefits that we consider are the best of our projects.
Each dependency that we add for our project contains other dependencies; most of the developers know this concept under the name of transitive dependencies. In many cases, this situation doesn’t present any problem because our dependency manager resolves in a good way the conflicts of versions between different libraries. Still, there are other cases when these conflicts produce some errors when we use our API/library.
Please let me clarify the stated above with the following examples:
In the case of figure 1, there isn’t a problem because all the libraries use the same version, so our dependency manager doesn’t need to do anything to resolve it. The problem appears in figure 2 because the libraries use different versions of the same library so Maven/Gradle tries to resolve the conflict between versions in the best way. In some cases, the resolution of the conflict with the version produces an error, the most common are: “ClassNotFoundException” — “MethodNotSupportedException” — “NoClassDefNotFound”, which appears when our dependency management tool takes a version without this particular class or method.
To resolve this problem, you have different alternatives to find and fix it. Here are the steps that I follow to find the solution:
We need to find which libraries produce the error. In most cases, the error in the console or the IDE (Eclipse/IntelliJ) shows the entire package of the class so you can find the jar which contains this class. For example:
In the case that the error is related to some class which not exists, you can use the entire package and use Findjar. This online search engine helps you to find a library that contains one particular Class.
With the name of the dependency which contains the class, you can find all the imports of this library. To do this there are some options depending on your dependency management tool:
To see all the tree of the dependencies in our project, you can run the following command: mvn dependency:tree
If you want to find just the libraries which include a certain dependency you can run: mvn dependency:tree
To see all the tree of the dependencies in our project you can run the following command: gradle dependencies — scan
When you detect which libraries contain the dependency that causes the problem, you need to exclude from our dependency management file (pom.xml or build.gradle) all the libraries which contain a different version of the dependency. In some cases, the library which produces the error not exists in the dependency tree because some of the libraries that you added have dependency marks as “provided” so you need to have this library in your pom to fix the problem.
You can use this solution when you run your application/library and the problem appears, but you have another way to detect this problem before that happens. There is a plugin which we can use in our dependency manager (Maven or Gradle) to check the problem with the dependencies; the following are the implementation for each dependency manager:
These plugins have a lot of features to use but the important in our case is DependencyConvergence, which shows all the possible problems with the libraries.
When you add in your project one of these plugins and run the validation if something is wrong the message that will appear in the console looks like this:
This output means that the project has two dependencies “junit-jupiter-engine” but with different versions. As I mentioned before you can resolve the problem exclude the dependency in “spring-boot-start-test” or tell to dependency management tool which version need to use it.
If you have a very old project and add the enforce plugin maybe you will discover a lot of conflicts to resolve which in some cases it’s impossible to resolve in a very short period but if you create a new project you can add the plugin from the beginning and prevent possible problems in the future.
You can see there are different alternatives to solve this problem. Now it’s up to you to decide which solution is the best one.