maven dependency conflicts and solutions

What is dependency conflict

Dependency conflict means that a certain jar package that the project depends on has multiple different versions, thus causing class package version conflicts.

Causes of dependency conflicts

Dependency conflicts are often caused by indirect dependencies between class packages. Each explicitly declared class package will depend on some other implicit class packages. These implicit class packages will be indirectly introduced by maven, causing class package conflicts.

How to resolve dependency conflicts

First check the class jars that cause dependency conflicts, and secondly find out the dependent class jars we don’t want and exclude them manually. The specific execution steps are as follows

1. Check dependency conflicts

a. Use the dependency:tree command to check version conflicts

mvn -Dverbose dependency:tree
1

When typing the above command, the following content will appear on the console

[INFO] org.example:hello:jar:1.0-SNAPSHOT
[INFO] + - org.springframework:spring-context:jar:5.2.7.RELEASE:compile
[INFO] | + - (org.springframework:spring-aop:jar:5.2.7.RELEASE:compile - omitted for conflict with 5.2.0.RELEASE)
[INFO] | + - org.springframework:spring-beans:jar:5.2.7.RELEASE:compile
[INFO] | | \- (org.springframework:spring-core:jar:5.2.7.RELEASE:compile - omitted for duplicate)
[INFO] | + - org.springframework:spring-core:jar:5.2.7.RELEASE:compile
[INFO] | | \- org.springframework:spring-jcl:jar:5.2.7.RELEASE:compile
[INFO] | \- org.springframework:spring-expression:jar:5.2.7.RELEASE:compile
[INFO] | \- (org.springframework:spring-core:jar:5.2.7.RELEASE:compile - omitted for duplicate)
[INFO] \- org.springframework:spring-aop:jar:5.2.0.RELEASE:compile
[INFO] + - (org.springframework:spring-beans:jar:5.2.0.RELEASE:compile - omitted for conflict with 5.2.7.RELEASE)
[INFO] \- (org.springframework:spring-core:jar:5.2.0.RELEASE:compile - omitted for conflict with 5.2.7.RELEASE)
123456789101112

Among them, omitted for duplicate means that a jar package is repeatedly relied on, and finally it says omitted for conflict with xxx, indicating that it conflicts with other jar package versions, and the jar package in this line will not be introduced. For example, there is a line above that says omitted for conflict with 5.2.7.RELEASE at the end, which means that the spring-core 5.2.0 version will not be referenced by the project, but the spring-core 5.2.7 version will be referenced by the project.

b. If it is an idea, you can install the maven helper plug-in to check for dependency conflicts.

The maven helper plug-in is installed successfully. When you click on pom.xml, you will find an additional Dependency Analyzer view, as follows
Dependency Analyzer.png
The icons of the above buttons have the following meanings:

  • Conflicts (view conflicts)
  • All Dependencies as List (View all dependencies in list form)
  • All Dependencies as Tree (View all dependencies in tree form)

The above picture shows that there are conflicts between 3 jars. Click on the conflicting jar to view which jar conflicts with it, as shown below
View conflicts.png

2. Resolve conflicts

The pom.xml shape of the project is as follows

 <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.7.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>5.2.0.RELEASE</version>
        </dependency>


    </dependencies>

12345678910111213141516

By looking at the dependency tree, we know that the project will reference the spring core jar package of 5.2.7.RELEASE, but not the jar package of 5.2.0. If we want to use the spring core package of version 5.2.0, what should we do?

a. Use the principle of first declarant taking precedence

Whoever defines it first will use its transitive dependency, that is, in the pom.xml file from top to bottom, the jar coordinates declared first will reference the jar’s transitive dependency first. Therefore, if we want to use the 5.2.0 version of the spring core package, we can change it to the following statement

 <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>5.2.0.RELEASE</version>
        </dependency>
        
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.7.RELEASE</version>
        </dependency>

    </dependencies>

123456789101112131415

View dependency tree

[INFO] org.example:hello:jar:1.0-SNAPSHOT
[INFO] + - org.springframework:spring-aop:jar:5.2.0.RELEASE:compile
[INFO] | + - org.springframework:spring-beans:jar:5.2.0.RELEASE:compile
[INFO] | | \- (org.springframework:spring-core:jar:5.2.0.RELEASE:compile - omitted for duplicate)
[INFO] | \- org.springframework:spring-core:jar:5.2.0.RELEASE:compile
[INFO] | \- org.springframework:spring-jcl:jar:5.2.0.RELEASE:compile
[INFO] \- org.springframework:spring-context:jar:5.2.7.RELEASE:compile
[INFO] + - (org.springframework:spring-aop:jar:5.2.7.RELEASE:compile - omitted for conflict with 5.2.0.RELEASE)
[INFO] + - (org.springframework:spring-beans:jar:5.2.7.RELEASE:compile - omitted for conflict with 5.2.0.RELEASE)
[INFO] + - (org.springframework:spring-core:jar:5.2.7.RELEASE:compile - omitted for conflict with 5.2.0.RELEASE)
[INFO] \- org.springframework:spring-expression:jar:5.2.7.RELEASE:compile
[INFO] \- (org.springframework:spring-core:jar:5.2.7.RELEASE:compile - omitted for conflict with 5.2.0.RELEASE)

12345678910111213

Through the dependency tree, we can see that the project has introduced the spring core package of version 5.2.0

b. Use the shortest path first principle

That is, direct dependency level is higher than transitive dependency. Therefore we can add the following content to the first pom.xml

 <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.7.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>5.2.0.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>5.2.0.RELEASE</version>
        </dependency>



    </dependencies>
12345678910111213141516171819202122

The one with the closest path is preferred.pngPass on As you can see from the picture, the project introduces the spring core 5.2.0 package.

c. Exclude dependencies

If it is an idea to exclude dependencies, you can use the maven helper plug-in to exclude them. Click on pom.xml, switch to the Dependency Analyzer view, select All Dependencies as Tree, click on the jar to be excluded, and the Execlude option will appear when you right-click, as follows
Remove dependencies.png
The effect it produces is the same as the following configuration

 <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.7.RELEASE</version>
            <exclusions>
                <exclusion>
                    <artifactId>spring-core</artifactId>
                    <groupId>org.springframework</groupId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>5.2.0.RELEASE</version>
        </dependency>

    </dependencies>

123456789101112131415161718192021

View dependencies.png
As you can see from the picture above, the project introduces the spring core 5.2.0 package

4. Version lock

Use dependencyManagement for version locking. DependencyManagement can uniformly manage the version number of the project to ensure that the dependencies and versions of each project in the application are consistent.

If we only want to use spring core 5.2.0 packages in our project, pom.xml can be changed to the following

<dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-core</artifactId>
                <version>5.2.0.RELEASE</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.7.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>5.2.0.RELEASE</version>
        </dependency>

    </dependencies>

12345678910111213141516171819202122232425

Version lock.png
As you can see from the picture above, the project introduces the spring core 5.2.0 package

Summary

In summary, this is how Maven troubleshoots dependency conflicts and how to solve them. For troubleshooting dependencies, I personally recommend using the maven helper plug-in. As for resolving dependency conflicts, I recommend using the version locking method. In addition, dependencyManagement only declares dependencies and does not Automatically implement the introduction, so the sub-project needs to explicitly declare the dependencies it needs to use