Maven Introduction – Part 3: Maven Dependency Mechanism

Dependency Management is a key feature of Maven. Maven Dependencies are identified by individual artifacts such as libraries or modules. It is not too difficult to manage dependencies for just a single project but, with multi-module projects, there are many things unclear.

This tutorial introduces the Maven Dependency Mechanism by which Maven helps us control them.

I. Transitive Dependencies

Transitive Dependencies allows us to include libraries that our dependencies require without discovering and specifying them, by reading POM files, find out all dependencies of the project, or projects inherit from their parents…

So, we just need to define dependencies in each project’s POM. Maven can do the rest automatically. It is no limit to the number of levels that dependencies can be gathered from, and will only cause a problem if there is any cyclic dependency discovered.

To avoid duplicate libraries, Maven provides some additional features that will limit which dependencies are included:
Dependency mediation specifies what version of a dependency will be used when there are multiple versions of an artifact:
+ it will use the version of the closest dependency to the project in the tree of dependencies.
+ we can specify a version by declaring it explicitly in project’s POM (without caring depth in the dependency tree).
+ if two dependency versions are at the same depth in the dependency tree, the first declaration wins.
For example, we habe Tree of dependencies
A -> B -> C -> D 2.0 and A -> E -> D 1.0
=> D 1.0 will be used when building A
=> if we add a dependency to D 2.0 in A, D 2.0 will be used.

Dependency management allows us to directly specify the versions of artifacts to be used when they are encountered in transitive dependencies.
In the example above, D was directly added to A even though it is not directly used by A. Instead, A can include D as a dependency in its dependencyManagement section and directly control which version of D is used when it is ever referenced.

Dependency scope allows us to only include dependencies appropriate for the current stage of the build.
We will see more detail below.

Excluded dependencies helps us exclude any transitive dependency using exclusion element.
For example, project A depends on project B, and project B depends on project C, project A owner can explicitly exclude project C as a dependency.

Optional dependencies allow us to mark any transitive dependency as optional using optional element.
For example, project A depends on project B, and project B depends on project C, project A owner can explicitly add project C as a dependency at his option. If the owner doesn’t add, the optional dependency is excluded by default.

II. Dependency Scope

Maven has 6 scopes available to restrict Transitive Dependencies:
compile: the default scope when there is no scope specified. It indicates a dependency available in all classpaths of a project. And that dependency is propagated to dependent projects.

provided is just like compile, but indicates that we expect the JDK or a web-Server/Container to provide the dependency at runtime. This scope is only available on the compilation and test classpath. This scope is not transitive.

runtime indicates that the dependency is not required for compilation but for execution (in the runtime and test classpaths, but not the compile classpath).

test indicates that the dependency is not required for normal use of the application, and is only available for the test compilation and execution phases. This scope is not transitive.

system is similar to provided, but we have to provide the JAR which contains it explicitly. So, the artifact is always available and is not looked up in a repository.

import (Maven 2.0.9 or later) is only supported when the dependency is of type pom in the dependencyManagement section. It indicates the dependency to be replaced with the dependencies in that specified POM’s dependencyManagement section.

III. Dependency Management

Dependency Management helps us centralize dependency information. When there are some projects that inherits a parent, we can put all common dependency information in the parent POM and make references to the artifacts in child POMs.

For example, we have two POMs of Project-1 and Project-2:

These dependency information can be put in the parent POM:

Two POMs now extend the same parent with simpler dependency information inside.
Dependency information for matching a reference against a dependencyManagement section are:
– groupId
– artifactId
– type
– classifier
We usually simplify the identity to groupId and artifactId, the default for type is jar, and classifier is null.
So, when type is is NOT a jar dependency, we must specify it.
In the example above, we indicate WAR as the type.

Related Posts

Got Something To Say:

Your email address will not be published. Required fields are marked *