Maven Dependency Tree is very helpful in understanding the project dependencies and resolving any conflicts because of different versions of a dependency.
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.
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.
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.
If the maven project has a lot of dependencies, it becomes hard to look for a specific artifact.
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] ------------------------------------------------------------------------
$
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] ------------------------------------------------------------------------
$
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
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
$
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.
Hi Pankaj, thanks for this post. Can you clarify what the plus, minus and slash signs before the jar in the tree signify?
- Akash
Thanks for this post
- Soumya