How to find out where a Maven dependency comes from

Maven can help you track down exactly why a certain library is appearing in your project.

One of the most common things you’ll do when developing a a modern Java application is add libraries and frameworks. You usually declare them as dependencies. But these dependencies can import other dependencies, too… so how do you know which dependencies your app is using, without going crazy?

Well, as it turns out, Maven can come to our rescue.

In Maven, the dependency:tree command will list all dependencies for a Java project.

But first, why?

Apps can get complicated really quickly.

If you’re building or supporting a big Java application, your app is probably using a bunch of libraries.

And those libraries use other libraries!

An app always starts out clean and simple, but it can become tiresome very quickly. Especially if you need to upgrade your app or resolve conflicts between the libraries you’re using.

(This is one of the problems that Spring Boot tries to resolve.)

But dependency:tree can help you manage your libraries, because it allows you to do things like this:

  • Find out which dependencies you’re pulling in

  • Find out which dependency is pulling in another dependency

  • Resolve version conflicts between different dependencies

  • Find out the exact versions of dependencies that you’re using in a project – this is really useful when you need to check if you’re exposed to a security vulnerability (e.g. the Log4Shell vulnerability)

Let’s see how it works.

List all dependencies

First - how do you list all of the dependencies that your Java application is using?

Perhaps you need to produce a report for someone?

It’s OK! We can find this information easily with Maven.

One of Maven’s main jobs is to handle your Java project’s dependencies. So when Maven runs, it builds a “tree” of all dependencies in your project.

If you tell Maven to print a dependency tree, you will be able to see all of the dependencies in your project.

To do this:

  1. Drop to a terminal.

  2. Change directory to your Java project (the location of your pom.xml file).

  3. Type: mvn dependency:tree

This prints the dependency tree.

It’s a text report which shows all of the dependencies in your project, both the direct and transitive dependencies.

If you’re not sure what the terms ‘direct’ and ‘transitive’ mean, then scroll further down for a quick guide to dependencies and how they work in Maven!

Here’s an example of what the output looks like:

[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ maven-dependency-tree-demo ---
[INFO] org.example:maven-dependency-tree-demo:jar:1.0-SNAPSHOT
[INFO] +- org.apache.logging.log4j:log4j-core:jar:2.17.2:compile
[INFO] |  \- org.apache.logging.log4j:log4j-api:jar:2.17.2:compile

How to read the output

The output looks a bit like gobbledegook but it’s actually telling us some important relationships between our project’s dependencies:

Output from mvn dependency:tree and what it means

Understanding the output from dependency:tree

So now we’ve got a list of the dependencies in our project. What if we want to track down the parent of a particular dependency?

Find the origin of a dependency

You can also use the dependency:tree command to find why a certain dependency was imported.

If you’ve not declared a dependency in your pom.xml, but it’s appearing in your project, it’s being imported somewhere as a transitive dependency.

You can see exactly which dependency is importing it, by looking at the dependency:tree report, and walking back up the “tree” to find its parent.

It’s a visual task, but we can make it a lot easier by filtering the report.

We add -Dincludes and give the name (artifactId) or the group of the dependency we’re looking for.

Let’s see an example…

Example: look for a specific artifact

For example, we want to look for a specific artifact from the org.apache.logging.log4j group called log4j-api.

We use -Dincludes, give the group name, then a colon : and then the artifact name:

mvn dependency:tree -Dincludes=org.apache.logging.log4j:log4j-api

The output tells us that we’re pulling in log4j-api (the bottom line) as a transitive dependency of log4j-core (the second-to-last line):

[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ maven-dependency-tree-demo ---
[INFO] org.example:maven-dependency-tree-demo:jar:1.0-SNAPSHOT
[INFO] \- org.apache.logging.log4j:log4j-core:jar:2.17.2:compile
[INFO]    \- org.apache.logging.log4j:log4j-api:jar:2.17.2:compile

Now you know where log4j-api is coming from.

This is all very good if you love the Terminal, but what if you want to do this in your Java IDE?

View Maven dependency tree in IntelliJ IDEA

If you’re a Java developer, you’re probably using an IDE to write code and manage your project.

In IntelliJ IDEA (which we think is the best Java IDE!), you can check out your project’s Maven dependencies without needing to drop to a Terminal.

You can get this information in the Maven Tool Window.

First go to View → Tool Windows → Maven, to make sure that the Maven window is visible.

Opening the Maven tool window in IntelliJ IDEA

Opening the Maven tool window

Then, you can see the tree of dependencies:

Viewing direct and transitive dependencies in IntelliJ IDEA

Viewing direct and transitive dependencies in IntelliJ IDEA

The top-level elements in the tree are your direct dependencies, and the child elements are the transitive dependencies.

How Maven dependencies work

If you’re new to Maven and Java development, some of these terms might be bit unfamiliar to you.

So here’s a quick “blagger’s guide” to Maven dependencies:

What is a dependency?

A dependency is some code which your project depends on. It could be a library, a framework, or even just a single class.

In Java, a dependency is normally packaged into a “.jar” file. (A jar file is basically a zip file which contains compiled Java classes, and some configuration files.)

In Maven, you declare your project’s dependencies in your pom.xml file.

You give the groupId, artifactId and version of the dependency you want to pull in:

<dependencies>
    <!-- Declaring one dependency -->
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <version>2.17.2</version>
    </dependency>

    <!-- More dependencies could go here -->
</dependencies>

Once you’ve added the dependency into your POM, Maven does the rest. At build time, it downloads the dependency, and makes it available to the build process.

What’s the difference between direct and transitive dependencies?

It’s probably good to understand that in computer programming, there are two types of dependencies, direct and transitive.

Direct dependencies

A direct dependency is one that you declare yourself:

→ e.g. “I want to use the Vert.x library”.

Transitive dependencies

When a dependency you’re using declares a dependency on another project, it’s called a transitive dependency.

→ e.g. “I want to use Vert.x, but it depends on the Jackson library.” (Jackson is the transitive dependency here)

How the dependency tree works

Each direct dependency can declare its own transitive dependencies. It declares this information in its POM file.

And then those transitive dependencies might have their own transitive dependencies, too.

Once your Java program is big enough, your dependencies will start to look like a tree structure.

Tree-like structure of Maven dependencies

The (Maven dependency) tree of life

And that’s exactly what Maven’s dependency:tree command tries to show for you.

So when you’re developing Java programs, we use a build tool (like Maven) to declare our direct dependencies, and the build tool sorts out all of the transitive dependencies for us (that’s what Maven does best!)

The mysteries of Maven

Maven can be quite complicated and, well, mysterious…..

To those who understand Maven, no explanation is necessary. To those who don't, no explanation is possible. (Stack Overflow)

Protector of the sacred knowledge of the Maven

Source: Stack Overflow

…but it’s full of lots of useful little features like dependency:tree, which is helpful.

So now you can list dependencies in your project, you’ll have better understanding about the libraries you’re actually using.

And you’ll have a bit more peace of mind, in case you need to resolve dependency conflicts or security alerts.

Comments? Share your Maven tips with the community below!

Keep on drinking that hot Java. ☕

Join the discussion

Got some thoughts on what you've just read? Want to know what other people think? Or is there anything technically wrong with the article? (We'd love to know so that we can correct it!) Join the conversation and leave a comment.

Comments are moderated.