One of the compelling reasons to use Maven is that it makes
the process of tracking down dependencies (and dependencies of
dependencies) very easy. When a project depends on an artifact produced by
another project we say that this artifact is a dependency. In the case of
a Java project, this can be as simple as a project depending on an
external dependency like Log4J or JUnit. While dependencies can model
external dependencies, they can also manage the dependencies between a set
of related projects. If project-a depends on
project-b, Maven is smart enough to know that
project-b must be built before
project-a.
Relationships are not only about dependencies and figuring out what one project needs to be able to build an artifact. Maven can model the relationship of a project to a parent, and the relationship of a project to submodules. This section gives an overview of the various relationships between projects and how such relationships are configured.
Coordinates define a unique location for a project.
Projects are related to one another using Maven Coordinates.
project-a doesn't just depend on
project-b; a project with a
groupId, artifactId, and
version depends on another project with a
groupId, artifactId, and
version. To review, a Maven Coordinate is made up of
three components:
- groupId
-
A
groupIdgroups a set of related artifacts. Group identifiers generally resemble a Java package name. For example, thegroupIdorg.apache.mavenis the base groupId for all artifacts produced by the Apache Maven project. Group identifiers are translated into paths in the Maven Repository; for example, the org.apache.maven groupId can be found in/maven2/org/apache/mavenon repo1.maven.org. - artifactId
-
The
artifactIdis the project's main identifier. When you generate an artifact, this artifact is going to be named with theartifactId. When you refer to a project, you are going to refer to it using theartifactId. TheartifactId,groupIdcombination must be unique. In other words, you can't have two separate projects with the sameartifactIdandgroupId;artifactIds are unique within a particulargroupId.Note
While '.'s are commonly used in
groupIds, you should try to avoid using them inartifactIds. This can cause issues when trying to parse a fully qualified name down into the subcomponents. - version
-
When an artifact is released, it is released with a version number. This version number is a numeric identifier such as "1.0", "1.1.1", or "1.1.2-alpha-01". You can also use what is known as a snapshot version. A snapshot version is a version for a component which is under development, snapshot version numbers always end in SNAPSHOT; for example, "1.0-SNAPSHOT", "1.1.1-SNAPSHOT", and "1-SNAPSHOT". Section 3.3.1.1, “Version Build Numbers” introduces versions and version ranges.
There is a fourth, less-used qualifier:
- classifier
-
You would use a classifier if you were releasing the same code but needed to produce two separate artifacts for technical reasons. For example, if you wanted to build two separate artifacts of a JAR, one compiled with the Java 1.4 compiler and another compiled with the Java 6 compiler, you might use the classifier to produce two separate JAR artifacts under the same groupId:artifactId:version combination. If your project uses native extensions, you might use the classifier to produce an artifact for each target platform. Classifiers are commonly used to package up an artifact's sources, JavaDocs or binary assemblies.
When we talk of dependencies in this book, we often use the
following shorthand notation to describe a dependency:
groupId:artifactId:version.
To refer to the 2.5 release of the Spring Framework, we would refer to
it as org.springframework:spring:2.5. When you ask
Maven to print out a list of dependencies with the Maven Dependency
plugin, you will also see that Maven tends to print out log messages
with this shorthand dependency notation.
There are going to be times when you want a project to inherit values from a parent POM. You might be building a large system, and you don't want to have to repeat the same dependency elements over and over again. You can avoid repeating yourself if your projects make use of inheritance via the parent element. When a project specifies a parent, it inherits the information in the parent project's POM. It can then override and add to the values specified in this parent POM.
All Maven POMs inherit values from a parent
POM. If a POM does not specify a
direct parent using the parent element, that
POM will inherit values from the Super
POM. Example 3.10, “Project Inheritance” shows the
parent element of project-a which
inherits the POM defined by the
a-parent project.
Example 3.10. Project Inheritance
<project>
<parent>
<groupId>com.training.killerapp</groupId>
<artifactId>a-parent</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>project-a</artifactId>
...
</project>
Running mvn help:effective-pom in
project-a would show a POM that is
the result of merging the Super POM with the
POM defined by a-parent and the
POM defined in project-a. The
implicit and explicit inheritance relationships for
project-a are shown in Figure 3.3, “Project Inheritance for a-parent and project-a”.
When a project specifies a parent project, Maven uses that
parent POM as a starting point before it reads the
current project's POM. It inherits everything,
including the groupId and version
number. You'll notice that project-a does not specify
either, both groupId and version
are inherited from a-parent. With a parent element,
all a POM really needs to define is an
artifactId. This isn't mandatory,
project-a could have a different
groupId and version, but by not
providing values, Maven will use the values specified in the parent
POM. If you start using Maven to manage and build
large multi-module projects, you will often be creating many projects
which share a common groupId and
version.
When you inherit a POM, you can choose to live with the inherited POM information or to selectively override it. The following is a list of items a Maven POM inherits from its parent POM:
-
identifiers (at least one of
groupIdorartifactIdmust be overridden.) -
dependencies
-
developers and contributors
-
plugin lists
-
reports lists
-
plugin executions (executions with matching ids are merged)
-
plugin configuration
When Maven inherits dependencies, it will add dependencies of
child projects to the dependencies defined in parent projects. You can
use this feature of Maven to specify widely used dependencies across all
projects which inherit from a top-level POM. For
example, if your system makes universal use of the Log4J logging
framework, you can list this dependency in your top-level
POM. Any projects which inherit
POM information from this project will automatically
have Log4J as a dependency. Similarly, if you need to make sure that
every project is using the same version of a Maven plugin, you can list
this Maven plugin version explicitly in a top-level parent
POM's pluginManagement
section.
Maven assumes that the parent POM is available
from the local repository, or available in the parent directory
(../pom.xml) of the current project. If neither
location is valid this default behavior may be overridden via the
relativePath element. For example, some organizations
prefer a flat project structure where a parent project's
pom.xml isn't in the parent directory of a child
project. It might be in a sibling directory to the project. If your
child project were in a directory ./project-a and
the parent project were in a directory named
./a-parent, you could specify the relative location
of parent-a's POM with the
following configuration:
<project>
<parent>
<groupId>org.sonatype.mavenbook</groupId>
<artifactId>a-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath>../a-parent/pom.xml</relativePath>
</parent>
<artifactId>project-a</artifactId>
</project>

