Analyzing dependencies in IntelliJ IDEA

Apr 30, 2019
Last Updated: Jul 02, 2019
Analyzing dependencies in IntelliJ IDEA
How to analyze dependencies in IDEA using Dependency Structure Matrix and other tools.

Dependency Matrix

This functionality is available only in IntelliJ IDEA Ultimate, not Community edition.

IDEA offers a useful tool to analyze internal dependencies in your project called the Dependency Structure Matrix. It can be used to analyze not only dependencies between packages, but also individual classes.

This can be very important as tightly coupled classes, and modules or even cyclic dependencies mean that your code is very hard to refactor and reuse.

Dependency Structure Matrix (or DSM for short) can help you visualize your dependencies and look for potential problems. First, make sure to build your project. Then, to launch the analysis go to Analyze → Analyze Dependency Matrix.... You need IDEA Ultimate edition and DSM Analysis bundled plugin enabled.

After the analysis is done, you'll see something similar to this:

Dependency matrix

To better understand the matrix, look at the following image.

Dependency matrix explained

IDEA skips the column labels to save the precious space, but it behaves as if they were there.

Each row and column represent the package. Each cell represents an intersection of a row and column - that is two packages. The number in the cell represents a number of dependencies one package has on another. That means one class from the source package using another class from the destination package. The darker the cell is, the more dependencies. If there are more than 99 dependencies, it shows ... instead of the number.

As long as the dependencies are blue, it is good as they are one way only. Cyclical dependencies would be shown in red, which is not good. But we'll see that later.

Visual aids

The matrix is a powerful tool, which can show a lot of information at once. However, it may be difficult to read at first, if you're not used to working with it. Especially with the columns hidden. Fortunately, there are visual aids, which can help you to better understand the dependencies.

If you hover your mouse cursor over a cell, it shows you with tooltip what is the dependency direction there.

DSM dependency tooltip

This can be useful, but there is more. You can click any package on the left (not an individual cell with dependency numbers), and IDEA will show you some more useful info.

DSM selected package

The row is highlighted, as well as the corresponding column representing the same package. On top of that, you can see that some other packages are highlighted by either yellow on green.

  • Yellow highlights packages on which the selected package depends
  • Green marks packages which depend on the selected package

In addition to selecting a whole package, you can also click individual cells. The color coding is the same, there is just one new concept. The purple cell represents dependencies between the same two packages but in the other direction.

DSM selected cell

We need to go deeper

So far we were working only on package level. This is no doubt useful, but often you need to go into more detail. Which means investigating also dependencies between single classes.

In the DSM view, it is simple, you can expand your packages to see their contents. This way you can see dependencies for all the potential sub-packages or even individual classes.

DSM expanded

Cyclic dependencies

So far, we covered only uni-directional dependencies. But something you should be really careful about are cyclic dependencies. In the DSM view, they are marked in red:

DSM Cyclic dependencies

You can see that class Owner has 15 dependencies on class Pet, while Pet has 5 dependencies on Owner.

Taking Action

DSM view in IDEA is not only a useful tool to visualize dependencies, but you can also take many useful actions directly from the context menu when right-clicking a cell or package.

You can even refactor your classes directly from the DSM view. If you click a cell with dependencies, you can call Find usages for dependencies. It will look for all the places in one of your classes/packages where the other class/package is used.

Let's look at an example to be more specific. We can find all the places in the service package, where anything from the vet package is used. The results are classified by type:

Find usages for dependencies

Now you can inspect the occurrences one by one and check whether you could improve the flow of your dependencies.

Analyzing Maven dependencies

This functionality is available only in IntelliJ IDEA Ultimate, not Community edition.

So far we covered only internal dependencies in your own code. However, you can run into all sorts of trouble also with external dependencies. That is your third-party libraries. It can get messy as you don't have only direct dependencies, but your libraries have dependencies of their own (transitive dependencies). You can encounter many problems such as dependency version conflicts of the same artifact or even cyclic dependencies. Maven offers you to generate dependency tree representation, which can help you in analyzing potential issues. You can simply call:

mvn dependency:tree -Dverbose -DoutputFile=dependencies.txt

It will output your dependency tree in plain text format, which can look something like this (here is the full example):

--- maven-dependency-plugin:3.0.2:tree (default-cli) @ spring-boot-actuator-example ---
com.vojtechruzicka:spring-boot-actuator-example:jar:1.0.0-SNAPSHOT
+- org.springframework.boot:spring-boot-starter-actuator:jar:2.0.3.RELEASE:compile
|  +- org.springframework.boot:spring-boot-starter:jar:2.0.3.RELEASE:compile
|  |  +- org.springframework.boot:spring-boot:jar:2.0.3.RELEASE:compile
|  |  +- org.springframework.boot:spring-boot-autoconfigure:jar:2.0.3.RELEASE:compile
|  |  +- org.springframework.boot:spring-boot-starter-logging:jar:2.0.3.RELEASE:compile
|  |  |  +- ch.qos.logback:logback-classic:jar:1.2.3:compile
|  |  |  |  \- ch.qos.logback:logback-core:jar:1.2.3:compile
|  |  |  +- org.apache.logging.log4j:log4j-to-slf4j:jar:2.10.0:compile
|  |  |  |  \- org.apache.logging.log4j:log4j-api:jar:2.10.0:compile
|  |  |  \- org.slf4j:jul-to-slf4j:jar:1.7.25:compile
|  |  +- javax.annotation:javax.annotation-api:jar:1.3.2:compile
|  |  \- org.yaml:snakeyaml:jar:1.19:runtime

In addition to plain text, it offers various other formats as output, which are better suited for representing dependency graph such as graphml or tgf.

You can specify some other parameters to help you with your investigation, but for larger projects, it can be cumbersome to work with dependency tree output directly.

Fortunately, IDEA offers a nice GUI tool to work with Maven dependency graphs. This tool is in IntelliJ for quite some time, but as of version 2019.1, it received some needed enhancements, which make it much more useful in projects with large dependency graphs.

To show the graph, go inside a pom.xml file and press Shift + Ctrl + Alt + U (or + + + U on Mac). Alternatively:

Right click → Diagrams → Show Dependencies

You'll see zoomed out dependency graph, where it is not possible to see individual item names unless you zoom in. Looking for individual items manually can be a lot of pain. Fortunately, you can use Find as usual using Ctrl + F.

We are able to locate a specific dependency easily now, but still, a lot of unrelated dependencies making the graph hard to read. Let's look into how to filter the dependencies to get rid of unwanted noise.

The first option is to show only direct neighbors. That is, only direct dependencies of the current item and only items that directly depend on the selected item.

Note that this works not only for single items, but you can select multiple items while holding Shift.

Another way to filter is to display the dependency chain leading from the root to the selected item(s).

IDEA does highlight conflicts for you in red. Still, it may be difficult to find if there is something wrong in a huge dependency tree. Fortunately, you can filter problematic parts only:

In the example above, you can see there is a conflict between JUnit versions. There is an explicit dependency to JUnit 3.8.1 and a different version transitively taken through spring-boot-starter-test.

Maven Helper plugin

If the graphical dependency tree is not your thing, there is an alternative for you. It's Maven Helper Plugin by Vojtech Krasa. It uses hierarchical text representation of dependencies, similar to mvn dependency:tree but with a nice dependency browser.

It is also a good alternative if you are using IDEA Community Edition or have an older version of IDEA, where the Maven dependency graph is way less useful.

To use the Dependency Analyzer offered by the plugin, simply open any pom.xml file. At the bottom of your editor, there is a new tab added by the editor called Dependency Analyzer.

Maven Helper Plugin

In the left panel, you can browse your dependencies (viewed either as list or tree). The right panel shows how selected dependency got into your application through the dependency chain. You can easily switch the view to show just conflicts.

Analyzing Gradle dependencies

Since version 2019.2, IDEA can finally show you dependency diagram not only for Maven, but also for Gradle. Yay! It works pretty much the same as Maven dependency diagram.

Just go to your build.gradle file and then press Shift + Ctrl + Alt + U (or + + + U on Mac). Or:

Right click → Diagrams → Show Dependencies

Conclusion

When you create an application, properly structuring your dependencies is very important as architecture with tight and tangled dependencies can be very hard to maintain, extend and modify. Fortunately, IDEA can help with a Dependency Structure Matrix, which provides a useful graphical view of your internal dependencies.

In addition to that, you need to make sure your external dependencies are covered as well, which you can achieve by utilizing a dependency graph for your dependency management system, such as Maven.




Let's connect