|Maven by Example
- 3.5. Core Concepts
Having just run Maven for the first time, it is a good time to introduce a few of the core concepts of Maven. In the previous example, you generated a project which consisted of a POM and some code assembled in the Maven standard directory layout. You then executed Maven with a lifecycle phase as an argument, which prompted Maven to execute a series of Maven plugin goals. Lastly, you installed a Maven artifact into your local repository. Wait? What is a "lifecycle"? What is a "local repository"? The following section defines some of Maven’s central concepts.
To execute a single Maven plugin goal, we used the syntax
$ mvn archetype:generate -DgroupId=org.sonatype.mavenbook.simple ... [INFO] [archetype:generate] ...
A Maven Plugin is a collection of one or more goals. Examples of Maven plugins can be simple core plugins like the Jar plugin, which contains goals for creating JAR files, Compiler plugin, which contains goals for compiling source code and unit tests, or the Surefire plugin, which contains goals for executing unit tests and generating reports. Other, more specialized Maven plugins include plugins like the Hibernate3 plugin for integration with the popular persistence library Hibernate, the JRuby plugin which allows you to execute ruby as part of a Maven build or to write Maven plugins in Ruby. Maven also provides for the ability to define custom plugins. A custom plugin can be written in Java, or a plugin can be written in any number of languages including Ant, Groovy, beanshell, and, as previously mentioned, Ruby.
A goal is a specific task that may be executed as a standalone goal or
along with other goals as part of a larger build. A goal is a “unit of
work” in Maven. Examples of goals include the
When referring to a plugin goal, we frequently use the shorthand
notation: pluginId:goalId. For example, when referring to the
Goals define parameters that can define sensible default values. In
The core of Maven has little to do with the specific tasks involved in your project’s build. By itself, Maven doesn’t know how to compile your code or even how to make a JAR file. It delegates all of this work to Maven plugins like the Compiler plugin and the Jar plugin, which are downloaded on an as-needed basis and periodically updated from the central Maven repository. When you download Maven, you are getting the core of Maven, which consists of a very basic shell that knows only how to parse the command line, manage a classpath, parse a POM file, and download Maven plugins as needed. By keeping the Compiler plugin separate from Maven’s core and providing for an update mechanism, Maven makes it easier for users to have access to the latest options in the compiler. In this way, Maven plugins allow for universal reusability of common build logic. You are not defining the compile task in a build file; you are using a Compiler plugin that is shared by every user of Maven. If there is an improvement to the Compiler plugin, every project that uses Maven can immediately benefit from this change. (And, if you don’t like the Compiler plugin, you can override it with your own implementation.)
The second command we ran in the previous section included an
execution of the Maven lifecycle. It begins with a phase to validate
the basic integrity of the project and ends with a phase that involves
deploying a project to production. Lifecycle phases are intentionally
vague, defined solely as validation, testing, or deployment, and they
may mean different things to different projects. For example, in a
project that produces a Java archive, the
Plugin goals can be attached to a lifecycle phase. As Maven moves
through the phases in a lifecycle, it will execute the goals attached
to each particular phase. Each phase may have zero or more goals bound
to it. In the previous section, when you ran
We know that the
To summarize, when we executed
mvn resources:resources \ compiler:compile \ resources:testResources \ compiler:testCompile \ surefire:test \ jar:jar \ install:install
It is much easier to execute lifecycle phases than it is to specify explicit goals on the command line, and the common lifecycle allows every project that uses Maven to adhere to a well-defined set of standards. The lifecycle is what allows a developer to jump from one Maven project to another without having to know very much about the details of each particular project’s build. If you can build one Maven project, you can build them all.
The Archetype plugin created a project with a file named
Maven coordinates define a set of identifiers which can be used to uniquely identify a project, a dependency, or a plugin in a Maven POM. Take a look at the following POM.
We’ve highlighted the Maven coordinates for this project: the
The packaging format of a project is also an important component in
the Maven coordinates, but it isn’t a part of a project’s unique
identifier. A project’s
These four elements become the key to locating and using one particular project in the vast space of other “Mavenized” projects . Maven repositories (public, private, and local) are organized according to these identifiers. When this project is installed into the local Maven repository, it immediately becomes locally available to any other project that wishes to use it. All you must do is add it as a dependency of another project using the unique Maven coordinates for a specific artifact.
When you run Maven for the first time, you will notice that Maven
downloads a number of files from a remote Maven repository. If the
simple project was the first time you ran Maven, the first thing it
will do is download the latest release of the Resources plugin when it
Often you will be writing a project which depends on libraries that are neither free nor publicly distributed. In this case you will need to either setup a custom repository inside your organization’s network or download and install the dependencies manually. The default remote repositories can be replaced or augmented with references to custom Maven repositories maintained by your organization. There are multiple products available to allow organizations to manage and maintain mirrors of the public Maven repositories.
What makes a Maven repository a Maven repository? A repository is a
collection of project artifacts stored in a directory structure that
closely matches a project’s Maven coordinates. You can see this
structure by opening up a web browser and browsing the central Maven
will see that an artifact with the coordinates
Maven downloads artifacts and plugins from a remote repository to your
local machine and stores these artifacts in your local Maven
repository. Once Maven has downloaded an artifact from the remote
Maven repository it never needs to download that artifact again as
Maven will always look for the artifact in the local repository before
looking elsewhere. On Windows XP, your local repository is likely in
In your local repository, you should be able to see the artifact
created by our simple project. If you run the
$ mvn install ... [INFO] [install:install] [INFO] Installing .../simple-1.0-SNAPSHOT.jar to \ ~/.m2/repository/com/sonatype/maven/simple/1.0-SNAPSHOT/ \ simple-1.0-SNAPSHOT.jar ...
As you can see from the output of this command, Maven installed our project’s JAR file into our local Maven repository. Maven uses the local repository to share dependencies across local projects. If you develop two projects—project A and project B—with project B depending on the artifact produced by project A, Maven will retrieve project A’s artifact from your local repository when it is building project B. Maven repositories are both a local cache of artifacts downloaded from a remote repository and a mechanism for allowing your projects to depend on each other.
In this chapter’s simple example, Maven resolved the coordinates of
the JUnit dependency
A more complex project would contain more than one dependency, or it
might contain dependencies that depend on other artifacts. Support for
transitive dependencies is one of Maven’s most powerful
features. Let’s say your project depends on a library that, in turn,
depends on 5 or 10 other libraries (Spring or Hibernate, for
example). Instead of having to track down all of these dependencies
and list them in your
Let’s take a look at a dependency which was downloaded to your local
repository when you ran the previous example. Look in your local
repository path under
When you install your project’s artifact in the local repository, you
will also notice that Maven publishes a slightly modified version of
A dependency in Maven isn’t just a JAR file; it’s a POM file that, in turn, may declare dependencies on other artifacts. These dependencies of dependencies are called transitive dependencies, and they are made possible by the fact that the Maven repository stores more than just bytecode; it stores metadata about artifacts.
In the previous figure, project A depends on projects B and C. Project B depends on project D, and project C depends on project E. The full set of direct and transitive dependencies for project A would be projects B, C, D, and E, but all project A had to do was define a dependency on B and C. Transitive dependencies can come in handy when your project relies on other projects with several small dependencies (like Hibernate, Apache Struts, or the Spring Framework). Maven also provides you with the ability to exclude transitive dependencies from being included in a project’s classpath.
Maven also provides for different dependency scopes. The simple
When you create a JAR for a project, dependencies are not bundled with
the generated artifact; they are used only for compilation. When you
use Maven to create a WAR or an EAR file, you can configure Maven to
bundle dependencies with the generated artifact, and you can also
configure it to exclude certain dependencies from the WAR file using
Another important feature of Maven is its ability to generate documentation and reports. In your simple project’s directory, execute the following command:
$ mvn site
This will execute the
On this site, you’ll notice that some default reports are available. A
unit test report communicates the success and failure of all unit
tests in the project. Another report generates Javadoc for the
project’s API. Maven provides a full range of configurable reports,
such as the Clover report that examines unit test coverage, the JXR
report that generates cross-referenced HTML source code listings
useful for code reviews, the PMD report that analyzes source code for
various coding problems, and the JDepend report that analyzes the
dependencies between packages in a codebase. You can customize site
reports by configuring which reports are included in a build via the