1. Overview
Working on large Maven projects can be intimidating, as can keeping track of all the dependencies between modules and libraries and resolving conflicts between them.
In this tutorial, we’ll learn about the Maven dependency graph or tree. First, we’ll learn how to create a dependency tree, filter dependencies, and create different output formats. Later, we’ll discuss visualizing different approaches to viewing the dependency tree graphically.
2. Project Setup
In real-life projects, the dependency tree grows very fast and becomes complex. However, for our example, we’ll create a small project with two modules, module1 and module2, each with two to three dependencies. Additionally, module1 depends on module2.
We’ll create our first module module2, and add the commons-collections, slf4j-api, spring-bean, and junit dependencies:
<dependencies>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.2</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-bean</artifactId>
<version>6.1.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
Now, we create a new module module1, and add commons-collections , spring-core, slf4j-api, and our module2 as dependencies:
<dependencies>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>6.1.1</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>com.baeldung.module2</groupId>
<artifactId>module2</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
We’re not concerned with the library functionalities here, but rather with how they’re derived for our project, to detect version conflicts, identify unnecessary dependencies, resolve build or run-time issues, and visualize the dependency tree.
3. Methods for Analyzing Dependency Graph or Tree
There are multiple ways to analyze the dependency tree or graph.
3.1. Using the Maven Dependency Plugin
maven-dependency-plugin displays the dependency tree for a given project in text format by default.
Let’s run the Maven command under the module2 directory to get the dependency tree for our module2:
$ mvn dependency:tree
// output snippet
[INFO] com.baeldung.module2:module2:jar:1.0
[INFO] +- commons-collections:commons-collections:jar:3.2.2:compile
[INFO] +- org.slf4j:slf4j-api:jar:1.7.25:compile
[INFO] +- org.springframework:spring-beans:jar:6.1.1:compile
[INFO] | \- org.springframework:spring-core:jar:6.1.1:compile
[INFO] | \- org.springframework:spring-jcl:jar:6.1.1:compile
[INFO] \- junit:junit:jar:4.13.2:test
[INFO] \- org.hamcrest:hamcrest-core:jar:1.3:test
Now, let’s run the Maven command under the module1 directory to get its dependency tree:
$ mvn dependency:tree
// output snippet
[INFO] com.baeldung.module1:module1:jar:1.0
[INFO] +- commons-collections:commons-collections:jar:3.2.2:compile
[INFO] +- org.springframework:spring-core:jar:6.1.1:compile
[INFO] | \- org.springframework:spring-jcl:jar:6.1.1:compile
[INFO] +- org.slf4j:slf4j-api:jar:1.7.25:compile
[INFO] \- com.baeldung.module2:module2:jar:1.0:compile
[INFO] \- org.springframework:spring-beans:jar:6.1.1:compile
By default, the output is in text format, and we can see how dependencies are getting included in our project.
We can filter the dependency tree output by excluding or including artifacts using this plugin.
For example, if we need to include only slf4j in the dependency tree, we can use the -Dinclude option to include all the dependencies:
$ mvn dependency:tree -Dincludes=org.slf4j
//output
[INFO] com.baeldung.module1:module1:jar:1.0
[INFO] \- org.slf4j:slf4j-api:jar:1.7.25:compile
If we need to exclude only slf4j in the tree, we can use the -Dexcludes option to exclude all the dependencies:
$ mvn dependency:tree -Dexcludes=org.slf4j
//output
[INFO] com.baeldung.module1:module1:jar:1.0
[INFO] +- commons-collections:commons-collections:jar:3.2.2:compile
[INFO] +- org.springframework:spring-core:jar:6.1.1:compile
[INFO] | \- org.springframework:spring-jcl:jar:6.1.1:compile
[INFO] \- com.baeldung.module2:module2:jar:1.0:compile
[INFO] \- org.springframework:spring-beans:jar:6.1.1:compile
Now, if we need to analyze all the dependencies in detail, we can use the –Dverbose option:
$ mvn dependency:tree -Dverbose
//output
[INFO] com.baeldung.module1:module1:jar:1.0
[INFO] +- commons-collections:commons-collections:jar:3.2.2:compile
[INFO] +- org.springframework:spring-core:jar:6.1.1:compile
[INFO] | \- org.springframework:spring-jcl:jar:6.1.1:compile
[INFO] +- org.slf4j:slf4j-api:jar:1.7.25:compile
[INFO] \- com.baeldung.module2:module2:jar:1.0:compile
[INFO] +- (commons-collections:commons-collections:jar:3.2.2:compile - omitted for duplicate)
[INFO] +- (org.slf4j:slf4j-api:jar:1.7.25:compile - omitted for duplicate)
[INFO] \- org.springframework:spring-beans:jar:6.1.1:compile
[INFO] \- (org.springframework:spring-core:jar:6.1.1:compile - omitted for duplicate)
Here, we can see that the spring-core from module1 is picked, and the one from module2 is removed.
Furthermore, for a complex project, reading this format is tedious. This plugin allows us to create another output format, like dot, graphml, or tgf, from the same dependency tree. It’s possible to visualize these output formats later using different editors.
Now, let’s get the same dependency tree in graphml format, and store the output in dependency.graphml:
$ mvn dependency:tree -DoutputType=graphml -DoutputFile=dependency.graphml
Here, we can use any online available graphml reader tool to visualize the dependency tree.
For our example, we’ll use the yED editor. We can import the dependency.graphml file in the yED editor. Although yED doesn’t format the graph by default, it offers multiple formats that we can use.
To customize, we’ll go to Layout > Hierarchic > Orientation > Left to Right > Apply. We can do a lot of other customizations on the tool as well, as per our needs:
3.2. Using Eclipse/IntelliJ like IDE
Most developers work with IDEs like Eclipse and IntelliJ, and these have the Maven dependency tree plugin.
First, we’ll start with the Eclipse m2e plugin, which provides a helpful dependency view.
After installing the plugin (if not already done), we’ll open module1‘s pom.xml and select Dependency Hierarchy from the tabs. The left side shows the hierarchy of jars in our project (same as the -Dverbose output). The resolved list is shown on the right. These are the jars used in our project:
IntelliJ also has a dependency analyzer tool. The default IntelliJ IDEA Community Edition provides a similar view as the Eclipse m2e plugin. We need to select the project, right-click on it, and select Dependency Analyser:
However, IntelliJ IDEA Ultimate provides more options and a more advanced graph. For this, we select the module1 project and right-click on it, select Maven, and click on Show Diagram:
3.3. Using Third-Party Lib
We’ve got a few third-party tools to help analyze the big dependency tree. They can import the graphml file created using the mvn dependency:tree and further use it for analyzing the graph visually.
Here are a few tools we can use to visualize complex dependency trees:
4. Conclusion
In this article, we discussed how to get the dependency tree of Maven projects and learned about filtering the dependency tree. Later, we looked at a few tools and plugins to visualize the dependency tree.
As always, the full source code with all examples is available over on GitHub.