What is the difference between dependencyManagement
and dependencies
?
I have seen the docs at Apache Maven web site.
It seems that a dependency def
If you have a parent-pom anyways, then in my opinion using <dependencyManagement>
just for controlling the version (and maybe scope) is a waste of space and confuses junior developers.
You will probably have properties for versions anyways, in some kind of parent-pom file. Why not just use this properties in the child pom's? That way you can still update a version in the property (within parent-pom) for all child projects at once. That has the same effect as <dependencyManagement>
just without <dependencyManagement>
.
In my opinion, <dependencyManagement>
should be used for "real" management of dependencies, like exclusions and the like.
The documentation on the Maven site is horrible. What dependencyManagement does is simply move your dependency definitions (version, exclusions, etc) up to the parent pom, then in the child poms you just have to put the groupId and artifactId. That's it (except for parent pom chaining and the like, but that's not really complicated either - dependencyManagement wins out over dependencies at the parent level - but if have a question about that or imports, the Maven documentation is a little better).
After reading all of the 'a', 'b', 'c' garbage on the Maven site and getting confused, I re-wrote their example. So if you had 2 projects (proj1 and proj2) which share a common dependency (betaShared) you could move that dependency up to the parent pom. While you are at it, you can also move up any other dependencies (alpha and charlie) but only if it makes sense for your project. So for the situation outlined in the prior sentences, here is the solution with dependencyManagement in the parent pom:
<!-- ParentProj pom -->
<project>
<dependencyManagement>
<dependencies>
<dependency> <!-- not much benefit defining alpha here, as we only use in 1 child, so optional -->
<groupId>alpha</groupId>
<artifactId>alpha</artifactId>
<version>1.0</version>
<exclusions>
<exclusion>
<groupId>zebra</groupId>
<artifactId>zebra</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>charlie</groupId> <!-- not much benefit defining charlie here, so optional -->
<artifactId>charlie</artifactId>
<version>1.0</version>
<type>war</type>
<scope>runtime</scope>
</dependency>
<dependency> <!-- defining betaShared here makes a lot of sense -->
<groupId>betaShared</groupId>
<artifactId>betaShared</artifactId>
<version>1.0</version>
<type>bar</type>
<scope>runtime</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
<!-- Child Proj1 pom -->
<project>
<dependencies>
<dependency>
<groupId>alpha</groupId>
<artifactId>alpha</artifactId> <!-- jar type IS DEFAULT, so no need to specify in child projects -->
</dependency>
<dependency>
<groupId>betaShared</groupId>
<artifactId>betaShared</artifactId>
<type>bar</type> <!-- This is not a jar dependency, so we must specify type. -->
</dependency>
</dependencies>
</project>
<!-- Child Proj2 -->
<project>
<dependencies>
<dependency>
<groupId>charlie</groupId>
<artifactId>charlie</artifactId>
<type>war</type> <!-- This is not a jar dependency, so we must specify type. -->
</dependency>
<dependency>
<groupId>betaShared</groupId>
<artifactId>betaShared</artifactId>
<type>bar</type> <!-- This is not a jar dependency, so we must specify type. -->
</dependency>
</dependencies>
</project>
There are a few answers outlining differences between <depedencies>
and <dependencyManagement>
tags with maven.
However, few points elaborated below in a concise way:
<dependencyManagement>
allows to consolidate all dependencies (used at child pom level) used across different modules -- clarity, central dependency version management<dependencyManagement>
allows to easily upgrade/downgrade dependencies based on need, in other scenario this needs to be exercised at every child pom level -- consistency<dependencies>
tag is always imported, while dependencies provided at <dependencyManagement>
in parent pom will be imported only if child pom has respective entry in its <dependencies>
tag.The difference between the two is best brought in what seems a necessary and sufficient definition of the dependencyManagement element available in Maven website docs:
dependencyManagement
"Default dependency information for projects that inherit from this one. The dependencies in this section are not immediately resolved. Instead, when a POM derived from this one declares a dependency described by a matching groupId and artifactId, the version and other values from this section are used for that dependency if they were not already specified." [ https://maven.apache.org/ref/3.6.1/maven-model/maven.html ]
It should be read along with some more information available on a different page:
“..the minimal set of information for matching a dependency reference against a dependencyManagement section is actually {groupId, artifactId, type, classifier}. In many cases, these dependencies will refer to jar artifacts with no classifier. This allows us to shorthand the identity set to {groupId, artifactId}, since the default for the type field is jar, and the default classifier is null.” [https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html ]
Thus, all the sub-elements (scope, exclusions etc.,) of a dependency element--other than groupId, artifactId, type, classifier, not just version--are available for lockdown/default at the point (and thus inherited from there onward) you specify the dependency within a dependencyElement. If you’d specified a dependency with the type and classifier sub-elements (see the first-cited webpage to check all sub-elements) as not jar and not null respectively, you’d need {groupId, artifactId, classifier, type} to reference (resolve) that dependency at any point in an inheritance originating from the dependencyManagement element. Else, {groupId, artifactId} would suffice if you do not intend to override the defaults for classifier and type (jar and null respectively). So default is a good keyword in that definition; any sub-element(s) (other than groupId, artifactId, classifier and type, of course) explicitly assigned value(s) at the point you reference a dependency override the defaults in the dependencyManagement element.
So, any dependency element outside of dependencyManagement, whether as a reference to some dependencyManagement element or as a standalone is immediately resolved (i.e. installed to the local repository and available for classpaths).
I'm fashionably late to this question, but I think it's worth a clearer response than the accepted one (which is correct, but doesn't emphasize the actual important part, which you need to deduce yourself).
In the parent POM, the main difference between the <dependencies>
and <dependencyManagement>
is this:
Artifacts specified in the <dependencies>
section will ALWAYS be included as a dependency of the child module(s).
Artifacts specified in the <dependencyManagement>
section, will only be included in the child module if they were also specified in the <dependencies>
section of the child module itself. Why is it good you ask? Because you specify the version and/or scope in the parent, and you can leave them out when specifying the dependencies in the child POM. This can help you use unified versions for dependencies for child modules, without specifying the version in each child module.
There's still one thing that is not highlighted enough, in my opinion, and that is unwanted inheritance.
Here's an incremental example:
I declare in my parent
pom:
<dependencies>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>19.0</version>
</dependency>
</dependencies>
boom! I have it in my Child A
, Child B
and Child C
modules:
version 18.0
in a Child B
if I want to.But what if I end up not needing guava in Child C
, and neither in the future Child D
and Child E
modules?
They will still inherit it and this is undesired! This is just like Java God Object code smell, where you inherit some useful bits from a class, and a tonn of unwanted stuff as well.
This is where <dependencyManagement>
comes into play. When you add this to your parent pom, all of your child modules STOP seeing it. And thus you are forced to go into each individual module that DOES need it and declare it again (Child A
and Child B
, without the version though).
And, obviously, you don't do it for Child C
, and thus your module remains lean.