Table of Contents
URL: https://www.progressiverobot.com/maven-dependency-tree-resolving-conflicts/
Maven Dependency Tree is very helpful in understanding the project dependencies and resolving any conflicts because of different versions of a dependency.
How to get the Maven Dependency Tree of a Project
We can run mvn dependency:tree command in the terminal to print the project dependency tree. For our example, I will be using the [Mockito Tutorial](/community/tutorials/mockito-tutorial) project. You can download the project from the GitHub repository. We are interested only in the project dependencies. The pom.xml has declared the following project dependencies.
<dependencies>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-runner</artifactId>
<version>1.2.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.2.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>2.19.0</version>
<scope>test</scope>
</dependency>
<!-- TestNG Dependencies -->
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.14.3</version>
<scope>test</scope>
</dependency>
</dependencies>
Let's see the output when we run the maven dependency tree command.
$ mvn dependency:tree
[INFO] Scanning for projects...
[INFO]
[INFO] -----------------------------
[INFO] Building Mockito-Examples 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ Mockito-Examples ---
[INFO] com.journaldev.mockito:Mockito-Examples:jar:1.0-SNAPSHOT
[INFO] +- org.junit.platform:junit-platform-runner:jar:1.2.0:test
[INFO] | +- org.apiguardian:apiguardian-api:jar:1.0.0:test
[INFO] | +- org.junit.platform:junit-platform-launcher:jar:1.2.0:test
[INFO] | +- org.junit.platform:junit-platform-suite-api:jar:1.2.0:test
[INFO] | | \- org.junit.platform:junit-platform-commons:jar:1.2.0:test
[INFO] | \- junit:junit:jar:4.12:test
[INFO] | \- org.hamcrest:hamcrest-core:jar:1.3:test
[INFO] +- org.junit.jupiter:junit-jupiter-engine:jar:5.2.0:test
[INFO] | +- org.junit.platform:junit-platform-engine:jar:1.2.0:test
[INFO] | | \- org.opentest4j:opentest4j:jar:1.1.0:test
[INFO] | \- org.junit.jupiter:junit-jupiter-api:jar:5.2.0:test
[INFO] +- org.mockito:mockito-junit-jupiter:jar:2.19.0:test
[INFO] | \- org.mockito:mockito-core:jar:2.19.0:test
[INFO] | +- net.bytebuddy:byte-buddy:jar:1.8.10:test
[INFO] | +- net.bytebuddy:byte-buddy-agent:jar:1.8.10:test
[INFO] | \- org.objenesis:objenesis:jar:2.6:test
[INFO] \- org.testng:testng:jar:6.14.3:test
[INFO] +- com.beust:jcommander:jar:1.72:test
[INFO] \- org.apache-extras.beanshell:bsh:jar:2.0b6:test
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.871 s
[INFO] Finished at: 2019-12-13T12:24:11+05:30
[INFO] ------------------------------------------------------------------------
$
The output is showing all the JARs being used to run this application. The output shows the dependencies groupId, artifactId, packaging, version, and scope.
Excluding a Dependency from the Maven Project Dependencies
If you look at the above dependency tree output, the JUnit 4 JAR is being pulled as a transitive dependency of junit-platform-runner. If you are planning to use JUnit 5 for writing test cases, it's a good idea to exclude JUnit 4 from the dependency to avoid any conflicts. We can exclude JUnit 4 JAR from the project dependencies using the exclusions tag. It has to be added to the dependency that is responsible for pulling it.
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-runner</artifactId>
<version>1.2.0</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
</exclusions>
</dependency>
Let's run the dependency tree command again. It should not show JUnit 4 JARs now.
Resolving Conflicts using Maven Dependency Tree Verbose Mode
When we build a maven project, the dependency version that is nearer to the project is selected. It can cause issues when you want a specific version but some other version is getting picked by the maven. We can use mvn dependency:tree -Dverbose command to print the dependency conflicts. It can help us in determining if there are any incompatibility issues with a JAR.
$ mvn dependency:tree -Dverbose
[INFO] Scanning for projects...
[INFO]
[INFO] -----------------------------
[INFO] Building Mockito-Examples 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ Mockito-Examples ---
[INFO] com.journaldev.mockito:Mockito-Examples:jar:1.0-SNAPSHOT
[INFO] +- org.junit.platform:junit-platform-runner:jar:1.2.0:test
[INFO] | +- org.apiguardian:apiguardian-api:jar:1.0.0:test
[INFO] | +- org.junit.platform:junit-platform-launcher:jar:1.2.0:test
[INFO] | | +- (org.apiguardian:apiguardian-api:jar:1.0.0:test - omitted for duplicate)
[INFO] | | \- (org.junit.platform:junit-platform-engine:jar:1.2.0:test - omitted for duplicate)
[INFO] | \- org.junit.platform:junit-platform-suite-api:jar:1.2.0:test
[INFO] | +- (org.apiguardian:apiguardian-api:jar:1.0.0:test - omitted for duplicate)
[INFO] | \- org.junit.platform:junit-platform-commons:jar:1.2.0:test
[INFO] | \- (org.apiguardian:apiguardian-api:jar:1.0.0:test - omitted for duplicate)
[INFO] +- org.junit.jupiter:junit-jupiter-engine:jar:5.2.0:test
[INFO] | +- (org.apiguardian:apiguardian-api:jar:1.0.0:test - omitted for duplicate)
[INFO] | +- org.junit.platform:junit-platform-engine:jar:1.2.0:test
[INFO] | | +- (org.apiguardian:apiguardian-api:jar:1.0.0:test - omitted for duplicate)
[INFO] | | +- (org.junit.platform:junit-platform-commons:jar:1.2.0:test - omitted for duplicate)
[INFO] | | \- org.opentest4j:opentest4j:jar:1.1.0:test
[INFO] | \- org.junit.jupiter:junit-jupiter-api:jar:5.2.0:test
[INFO] | +- (org.apiguardian:apiguardian-api:jar:1.0.0:test - omitted for duplicate)
[INFO] | +- (org.opentest4j:opentest4j:jar:1.1.0:test - omitted for duplicate)
[INFO] | \- (org.junit.platform:junit-platform-commons:jar:1.2.0:test - omitted for duplicate)
[INFO] +- org.mockito:mockito-junit-jupiter:jar:2.19.0:test
[INFO] | +- org.mockito:mockito-core:jar:2.19.0:test
[INFO] | | +- net.bytebuddy:byte-buddy:jar:1.8.10:test
[INFO] | | +- net.bytebuddy:byte-buddy-agent:jar:1.8.10:test
[INFO] | | \- org.objenesis:objenesis:jar:2.6:test
[INFO] | \- (org.junit.jupiter:junit-jupiter-api:jar:5.1.0:test - omitted for conflict with 5.2.0)
[INFO] \- org.testng:testng:jar:6.14.3:test
[INFO] +- com.beust:jcommander:jar:1.72:test
[INFO] \- org.apache-extras.beanshell:bsh:jar:2.0b6:test
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.018 s
[INFO] Finished at: 2019-12-13T12:58:07+05:30
[INFO] ------------------------------------------------------------------------
$
The output line (org.junit.jupiter:junit-jupiter-api:jar:5.1.0:test – omitted for conflict with 5.2.0) tells us that this version of JAR is dropped in favor of another version. If you want to use junit-jupiter-api version 5.1.0, just add it to the project maven dependencies. Since Maven resolves version conflicts with a nearest-wins strategy, the direct dependencies are always included in the project.
Filtering the Maven Dependency Tree
If the maven project has a lot of dependencies, it becomes hard to look for a specific artifact.
-Dincludes
We can use the -Dincludes option to include only specific dependencies from the output. The syntax of the filtering pattern is [groupId]:[artifactId]:[type]:[version]. Each of the pattern segment is optional and supports full and partial * wildcards.
$ mvn dependency:tree -Dverbose -Dincludes=org.junit.jupiter:junit-jupiter-api
[INFO] Scanning for projects...
[INFO]
[INFO] -----------------------------
[INFO] Building Mockito-Examples 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ Mockito-Examples ---
[INFO] com.journaldev.mockito:Mockito-Examples:jar:1.0-SNAPSHOT
[INFO] +- org.junit.jupiter:junit-jupiter-engine:jar:5.2.0:test
[INFO] | \- org.junit.jupiter:junit-jupiter-api:jar:5.2.0:test
[INFO] \- org.mockito:mockito-junit-jupiter:jar:2.19.0:test
[INFO] \- (org.junit.jupiter:junit-jupiter-api:jar:5.1.0:test - omitted for conflict with 5.2.0)
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.981 s
[INFO] Finished at: 2019-12-13T13:04:04+05:30
[INFO] ------------------------------------------------------------------------
$
-Dexcludes
This is used to remove given dependencies from the dependency tree output. The pattern is the same as -Dincludes option. We can use a comma to specify multiple patterns to include or exclude from the dependency tree.
$ mvn dependency:tree -Dexcludes=org.junit.jupiter:junit-jupiter-api
[INFO] Scanning for projects...
[INFO]
[INFO] -----------------------------
[INFO] Building Mockito-Examples 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ Mockito-Examples ---
[INFO] com.journaldev.mockito:Mockito-Examples:jar:1.0-SNAPSHOT
[INFO] +- org.junit.platform:junit-platform-runner:jar:1.2.0:test
[INFO] | +- org.apiguardian:apiguardian-api:jar:1.0.0:test
[INFO] | +- org.junit.platform:junit-platform-launcher:jar:1.2.0:test
[INFO] | \- org.junit.platform:junit-platform-suite-api:jar:1.2.0:test
[INFO] | \- org.junit.platform:junit-platform-commons:jar:1.2.0:test
[INFO] +- org.junit.jupiter:junit-jupiter-engine:jar:5.2.0:test
[INFO] | \- org.junit.platform:junit-platform-engine:jar:1.2.0:test
[INFO] | \- org.opentest4j:opentest4j:jar:1.1.0:test
[INFO] +- org.mockito:mockito-junit-jupiter:jar:2.19.0:test
[INFO] | \- org.mockito:mockito-core:jar:2.19.0:test
[INFO] | +- net.bytebuddy:byte-buddy:jar:1.8.10:test
[INFO] | +- net.bytebuddy:byte-buddy-agent:jar:1.8.10:test
[INFO] | \- org.objenesis:objenesis:jar:2.6:test
[INFO] \- org.testng:testng:jar:6.14.3:test
[INFO] +- com.beust:jcommander:jar:1.72:test
[INFO] \- org.apache-extras.beanshell:bsh:jar:2.0b6:test
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.925 s
[INFO] Finished at: 2019-12-13T13:55:22+05:30
[INFO] ------------------------------------------------------------------------
$
Maven Dependency Tree in Eclipse IDE
Eclipse pom.xml "Dependency Hierarchy" tab shows the dependency tree of the project. It has two sides – the left side shows verbose output and the right side shows the resolved dependencies. We can use the "Filter" option to look for a specific dependency.
Further Reading: [Using Maven in Eclipse IDE](/community/tutorials/maven-eclipse-ide)
Saving Dependency Tree to a File
We can use -DoutputFile option to specify the file to save the dependency tree output.
$ mvn dependency:tree -DoutputFile=dependency-tree.txt
[INFO] Scanning for projects...
[INFO]
[INFO] -----------------------------
[INFO] Building Mockito-Examples 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ Mockito-Examples ---
[INFO] Wrote dependency tree to: /Users/pankaj/Desktop/maven-examples/Mockito-Examples/dependency-tree.txt
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.862 s
[INFO] Finished at: 2019-12-13T15:27:51+05:30
[INFO] ------------------------------------------------------------------------
$
$ cat dependency-tree.txt
com.journaldev.mockito:Mockito-Examples:jar:1.0-SNAPSHOT
+- org.junit.platform:junit-platform-runner:jar:1.2.0:test
| +- org.apiguardian:apiguardian-api:jar:1.0.0:test
| +- org.junit.platform:junit-platform-launcher:jar:1.2.0:test
| \- org.junit.platform:junit-platform-suite-api:jar:1.2.0:test
| \- org.junit.platform:junit-platform-commons:jar:1.2.0:test
+- org.junit.jupiter:junit-jupiter-engine:jar:5.2.0:test
| +- org.junit.platform:junit-platform-engine:jar:1.2.0:test
| | \- org.opentest4j:opentest4j:jar:1.1.0:test
| \- org.junit.jupiter:junit-jupiter-api:jar:5.2.0:test
+- org.mockito:mockito-junit-jupiter:jar:2.19.0:test
| \- org.mockito:mockito-core:jar:2.19.0:test
| +- net.bytebuddy:byte-buddy:jar:1.8.10:test
| +- net.bytebuddy:byte-buddy-agent:jar:1.8.10:test
| \- org.objenesis:objenesis:jar:2.6:test
\- org.testng:testng:jar:6.14.3:test
+- com.beust:jcommander:jar:1.72:test
\- org.apache-extras.beanshell:bsh:jar:2.0b6:test
$