Multi-module project dependency management in Maven

Just a quick one here on an old topic: dependency management with Maven. This is definitely not a new topic so I won’t waste your time on it too much. There is however one finding I would like to share which has improved my workflow in large projects.

The Problem

As you probably know, Maven manages dependencies. In multi-module projects this can be cumbersome and to improve workflow you can use the dependency management section to describe the version of a certain dependency in all its child projects.

Now for the tricky part: when you have a multi-module project BUT not all children of the parent are in the same project structure (so in different git repos for example), the management of dependencies can become difficult, eventhough you use the dependencyManagement section in the parent. This is due to the fact that the inheritance structure of the poms makes it difficult to see whether the (sub-)module is still at the correct parent version and which dependencies it actually has. IDEs help, but only so much.
At the same time, when you update the parent version because of a dependency version update, this might have unexpected results in certain children (incompatibilities and so on), so you cannot update all parent versions in all children without issues.

The Fix

To fix this, I’ve recently started to use a new way that I like very much so far. I didn’t invent this, it’s been around for a long time, but I stumbled upon the concept while using Spring Boot.
The idea is to use a separate project that is not part of the hierarchy but that only defines dependencies in a dependencyManagement section and gets included at the (sub-)module level dependencyManagement section like this:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>nl.bdln.projects</groupId>
            <artifactId>all-dependencies</artifactId>
            <version>1.3.15</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

This has the effect that the hierarchy does not define the dependencies used in the (sub-)module, but the included version of the dependency pom does. Therefore, you can update the dependencies on a per-module basis, while still using a fixed set of (approved/consistent) dependencies. Basically, the dependency versions are decoupled from the pom inheritance, which is easier to handle

Remarks

  • the parent pluginManagement section should no longer define dependency versions (it should be empty) to avoid conflicts and uncertainties
  • you can only update the main project when all children have been updated (this was always the case, but is now clear)
  • it’s still a requirement to make sure each (sub-)module is backwards compatible with the older dependency pom version, since the main project might still be at an older version of the main dependencies pom.
  • the approach described above does not hold for the pluginManagement section of the parent pom build section: it’s actually useful to describe the plugins here, since they change relatively little over time and are linked to the build requirements more than to the actual project

See also