Maven Dependency Tree – Resolving Conflicts

Filed Under: Maven
Apache Maven Dependency Tree

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 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.

Maven Dependency Tree

Maven Dependency Tree

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.

Eclipse Pom Dependency Hierarchy

Eclipse Pom Dependency Hierarchy

Further Reading: Using Maven in 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
$

References

Comments

  1. Akash says:

    Hi Pankaj, thanks for this post. Can you clarify what the plus, minus and slash signs before the jar in the tree signify?

  2. Soumya says:

    Thanks for this post

Leave a Reply

Your email address will not be published. Required fields are marked *

close
Generic selectors
Exact matches only
Search in title
Search in content
Search in posts
Search in pages