
In this chapter we introduce a simple project created from scratch using the Maven Archetype plugin. This simple application provides us with the opportunity to introduce some core Maven concepts while you follow along with the development of this simple project.
Before you can start using Maven for complex, multi-module builds, we have to start with the basics. If you've used Maven before, you'll notice that it does a good job of taking care of the details. Your builds tend to "just work", and you only really need to dive into the details of Maven when you need to customize the default behavior or write a custom plugin. On the other hand, when you do need to dive into the details of Maven, a thorough understanding of the core concepts is essential. This chapter aims to introduce you to the simplest possible Maven project and then to introduce you to some of the core concepts that make Maven a solid build platform. After reading this chapter, you'll have a fundamental understanding of the build lifecycle, Maven repositories, dependency management, and the Project Object Model (POM).
This chapter develops a very simple example which will be used to
explore core concepts of Maven. If you follow the steps described in
this chapter, you shouldn't need to download the examples to recreate
the code produced by the Maven. We will be using the Maven Archetype
plugin to create this simple project and this chapter doesn't modify the
project in any way. If you would prefer to read this chapter with the
final example source code, this chapter's example project may be
downloaded with the book's example code at http://www.sonatype.com/book/mvn-examples-1.0.zip
or http://www.sonatype.com/book/mvn-examples-1.0.tar.gz.
Unzip this archive in any directory, and then go to the
ch03/ directory. In the ch03/
directory you will see a directory named simple/
which contains the source code for this chapter. If you wish to follow
along with the example code in a web browser, go to http://www.sonatype.com/book/examples-1.0
and click on the ch03/ directory.
To start a new Maven project, use the Maven Archetype plugin from the command line.
$ mvn archetype:create -DgroupId=org.sonatype.mavenbook.ch03 \
-DartifactId=simple \
-DpackageName=org.sonatype.mavenbook
[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'archetype'.
[INFO] artifact org.apache.maven.plugins:maven-archetype-plugin: checking for
updates from central
[INFO] -----------------------------------------------------------------------
[INFO] Building Maven Default Project
[INFO] task-segment: [archetype:create] (aggregator-style)
[INFO] --------------------------------------------------------------------
[INFO] [archetype:create]
[INFO] artifact org.apache.maven.archetypes:maven-archetype-quickstart: \
checking for updates from central
[INFO] Parameter: groupId, Value: org.sonatype.mavenbook.ch03
[INFO] Parameter: packageName, Value: org.sonatype.mavenbook
[INFO] Parameter: basedir, Value: /Users/tobrien/svnw/sonatype/examples
[INFO] Parameter: package, Value: org.sonatype.mavenbook
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] Parameter: artifactId, Value: simple
[INFO] * End of debug info from resources from generated POM *
[INFO] Archetype created in dir: /Users/tobrien/svnw/sonatype/examples/simple
mvn is the Maven 2 command.
archetype:create is called a Maven goal. If you are
familiar with Apache Ant, a Maven goal is analogous to an Ant target; both
describe a unit of work to be completed in a build. The
-Dname=value pairs are arguments that are passed to the
goal and take the form of -D properties, similar to the
system property options you might pass to the Java Virtual Machine via the
command line. The purpose of the archetype:create goal
was to quickly create a project from an archetype. In this context an
archetype is defined as "an original model or type after which other
similar things are patterned; a prototype"[2][2]. There are a number of archetypes available in Maven for
anything from a simple Swing application to a complex web application. In
this chapter, we are going to use the most basic archetype to create a
simple skeleton starter project. The plugin is the prefix "archetype", and
the goal is "create".
Once we've generated a project, take a look at the directory structure Maven created under the simple directory:
simple/simple/pom.xml
/src/ /src/main/
/main/java /src/test/
/test/java
This generated directory adheres to the Maven Standard Directory Layout, we'll get into more of the details later, but, for now, let's just try to understand these few basic directories:
The Maven Archetype plugin generated a single class
org.sonatype.mavenbook.App which is a thirteen line
Java class with a static main function that prints out a message:
package org.sonatype.mavenbook;
/**
* Hello world!
*
*/
public class App
{
public static void main( String[] args )
{
System.out.println( "Hello World!" );
}
}
The simplest Maven archetype generates the simplest possible program: a program which prints "Hello World!" to standard output.
Once you have created the project with the Maven Archetype plugin by
following the directions from Section 3.2, “Creating a Simple Project”, you
will want to build and package the application. To build and package this
application, run mvn install from the directory that
contains the pom.xml.
$ mvn install
[INFO] Scanning for projects...
[INFO] ----------------------------------------------------------------------
[INFO] Building simple
[INFO] task-segment: [install]
[INFO] ----------------------------------------------------------------------
[INFO] [resources:resources]
[INFO] Using default encoding to copy filtered resources.
[INFO] [compiler:compile]
[INFO] Compiling 1 source file to /simple/target/classes
[INFO] [resources:testResources]
[INFO] Using default encoding to copy filtered resources.
[INFO] [compiler:testCompile]
[INFO] Compiling 1 source file to /simple/target/test-classes
[INFO] [surefire:test]
[INFO] Surefire report directory: /simple/target/surefire-reports
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running org.sonatype.mavenbook.AppTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.105 sec
Results :
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO] [jar:jar]
[INFO] Building jar: /simple/target/simple-1.0-SNAPSHOT.jar
[INFO] [install:install]
[INFO] Installing /simple/target/simple-1.0-SNAPSHOT.jar to \
~/.m2/repository/org/sonatype/mavenbook/ch03/simple/1.0-SNAPSHOT/ \
simple-1.0-SNAPSHOT.jar
You've just created, compiled, tested, packaged, and installed the simplest possible Maven project. To prove to yourself that this program works, run it from the command line.
$ java -cp target/simple-1.0-SNAPSHOT.jar org.sonatype.mavenbook.App
Hello World!
When Maven executes it looks to the Project Object Model
(POM) for information about the project. The
POM answers such questions as: What type of project is
this? What is the project's name? Are there any build customizations for
this project? This is the default pom.xml file
created by the Maven Archetype plugin's create goal.
Example 3.1. Simple project's pom.xml file
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.sonatype.mavenbook.ch03</groupId> <artifactId>simple</artifactId> <packaging>jar</packaging> <version>1.0-SNAPSHOT</version> <name>simple</name> <url>http://maven.apache.org</url> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> </dependencies> </project>
This pom.xml file is the most basic
POM you will ever deal with for a Maven project,
usually a POM file is considerably more complex:
defining multiple dependencies and customizing plugin behavior. The first
few elements—groupId, artifactId,
packaging, version—are what is known
as the Maven coordinates which uniquely identify a project.
name and url are descriptive
elements of the POM providing a human readable name and
associating the project with a web site. The
dependencies element defines a single, test-scoped
dependency on a unit testing framework called JUnit. These topics will be
further introduced in Section 3.5, “Core Concepts”, all you need
to know, at this point, is that the pom.xml is the
file that makes Maven go.
Maven always executes against an effective POM, a
combination of settings from this project's pom.xml,
all parent POMs, a super-POM defined
within Maven, user-defined settings, and active profiles. All projects
ultimately extend the super-POM, which defines a set of
sensible default configuration settings and which is fully explained in
Chapter 9, The Project Object Model. While your project might have a
relatively minimal pom.xml, the contents of your
project's POM are interpolated with the contents of all
parent POMs, user settings, and any active profiles. To
see this "effective" POM, run the following command in
the simple project's base directory.
$ mvn help:effective-pomWhen you run this, you should see a much larger POM which exposes the default settings of Maven. This goal can come in handy if you are trying to debug a build and want to see how all of the current project's ancestor POMs are contributing to the effective POM. For more information about the Maven Help plugin, see Section 2.7, “Using the Maven Help Plugin”.
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 execute 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 follow section defines some of Maven's central concepts.
In the previous section, we ran Maven with two different types of
command-line arguments. The first command was a single plugin goal, the
create goal of the Archetype plugin. The second
execution of Maven was a lifecycle phase - install.
To execute a single Maven Plugin goal, we used the syntax mvn
archetype:create where archetype is the
identifier of a plugin and create is the identifier
of a goal. When Maven executes a Plugin goal, it prints out the plugin
identifier and goal identifier to standard output:
$ mvn archetype:create -DgroupId=org.sonatype.mavenbook.ch03 \ -DartifactId=simple \ -DpackageName=org.sonatype.mavenbook ... [INFO] [archetype:create] [INFO] artifact org.apache.maven.archetypes:maven-archetype-quickstart: \ checking for updates from central ...
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
compile goal in the Compiler plugin which compiles
all of the source code for a project, or the test
goal of the Surefire plugin which can execute unit tests. Goals are
configured via configuration properties which can be used to customize
behavior. For example, the compile goal of the
Compiler plugin defines a set of configuration parameters which allow
you to specify the target JDK version or whether to use the compiler
optimizations. In the previous example, we passed in the configuration
parameters groupId and artifactId
to the create goal of the Archetype plugin via the
command-line parameters
-DgroupId=org.sonatype.mavenbook.ch03 and
-DartifactId=simple. We also passed the
packageName parameter to the create goal as
org.sonatype.mavenbook. If we had omitted the
packageName parameter, the package name would have
defaulted to org.sonatype.mavenbook.ch03.
When referring to a plugin goal, we frequently use the
shorthand notation: pluginId:goalId. For example,
when referring to the create plugin in the Archetype plugin, we
write archetype:create.
Goals define parameters which can define sensible default values.
In the archetype:create example, we did not specify
what kind of archetype the goal was to create on our command line, we
simply passed in a groupId and an
artifactId. This is our first brush with
convention over configuration. The convention, or
default, for the create goal is to create a simple
project called Quickstart. The create goal defines a
configuration property archetypeArtifactId which has
a default value of maven-archetype-quickstart. The
Quickstart archetype generates a minimal project shell that contains a
POM and a single class. The Archetype plugin is far
more powerful than this first example suggests, but it is a great way to
get new projects started fast. Later in this book, we're going to show
you how the Archetype plugin can be used to generate more complex
projects like web applications and how you can use the Archetype plugin
to define your own set of projects.
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, it is easier for users of Maven 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 which is shared by every user of Maven. If there is an improvement to the Compiler plugin, every project which 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 was mvn
package. This command-line didn't specify a plugin goal;
instead, it specified a Maven Lifecycle phase. A phase is a step in what
Maven calls the "build lifecycle". The build lifecycle is an ordered
sequence of phases involved in building a project. Maven can support a
number of different lifecycles, but the most often used lifecycle is the
default Maven lifecycle which begins with a phase to validate the basic
integrity of the project and ends with a phase which involves deploying
a project to production. Lifecycle phases are left purposefully vague,
defined solely as validation, testing, or deployment and they may mean
different things to different projects. For example, the
package phase in a project which produces a
JAR means "package this project into a jar", in a
project which produces a web application, the package
phase may produce a WAR file. Figure 3.2, “A Lifecycle is a Sequence of Phases” shows a simplified representation of
the default Maven lifecycle.
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 mvn
package, you might have noticed that more than one goal was
executed. Examine the output after running mvn
package, and take note of the various goals which are
executed. When this simple example reached the
package phase, it executed the jar
goal in the Jar plugin. Since our simple quickstart project has (by
default) a jar packaging type, then the
jar:jar goal is bound to the package phase.
We know that the package phase is going to create a
JAR file for a project with jar
packaging. But, what of the goals preceding it, like
compiler:compile and
surefire:test? These goals are executed as Maven
steps through the phases preceding package in the
Maven lifecycle; executing a phase will first execute all proceeding
phases in order ending with the phase specified on the command-line.
Each phase corresponds to zero or more goals, and since we haven't
performed any plugin configuration or customization, this example binds
a set of standard plugin goals to the default lifecycle. The following
goals are executed in order when Maven walks through the default
lifecycle ending on package:
resources:resourcesThe resources goal of the Resources
plugin is bound to the resources phase. This
goal copies all of the resources from
src/main/resources and any other configured
resource directories to the output directory.
compiler:compileThe compile goal of the Compiler plugin
is bound to the compile phase. This goal
compiles all of the source code from
src/main/java or any other configured source
directories to the output directory.
resources:testResourcesThe testResources goal of the Resources
plugin is bound to the test-resources phase.
This goal copies all of the resources from
src/test/resources and any other configured
test resource directories to a test output directory.
compiler:testCompileThe testCompile goal of the Compiler
plugin is bound to the test-compile phase. This
goal compiles test cases from src/test/java
and any other configured test source directories to a test output
directory.
surefire:testThe test goal of the Surefire plugin is
bound to the test phase. This goal executes all
of the tests and creates output files that capture detailed
results. By default this goal will terminate a build if there is a
test failure.
jar:jarThe jar goal of the Jar plugin is bound
to the package phase. This goal packages the
output directory into a JAR file.
To summarize, when we executed mvn package, Maven executes all phases up to package, and in the process of stepping through the life cycle phases it executes all goals bound to each phase. Instead of executing a Maven lifecycle goal you could achieve the same results by specifying a sequence of plugin goals as follows:
mvn resources:resources \
compiler:compile \
resources:testResources \
compiler:testCompile \
surefire:test \
jar:jar
Executing the package phase is preferable to
keeping track of all of the goals involved in a particular build, it
also 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
pom.xml. This is the Project Object Model
(POM), a declarative description of a project. When
Maven executes a goal, each goal has access to the information defined
in a project's POM. When the
jar:jar goal needs to create a JAR
file, it looks to the POM to find out what the Jar
file's name is. When the compiler:compile tasks
compiles Java source code into bytecode, it looks to the
POM to see if there are any parameters for the
compile goal. Goals execute in the context of a POM.
Goals are actions we wish to take upon a project, and a project is
defined by a POM. The POM names
the project, provides a set of unique identifiers (coordinates) for a
project, and defines the relationships between this project and others
through dependencies, parents, and prerequisites. A
POM can also customize plugin behavior and supply
information about the community and developers involved in a
project.
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
groupId, artifactId,
version and packaging. These
combined identifiers make up a project's coordinates[3].[3]Just like in any other coordinate system, a Maven
coordinate is an address for a specific point in "space": from general
to specific. Maven pinpoints a project via its coordinates when one
project relates to another, either as a dependency, a plugin, or a
parent project reference. Maven coordinates are often written using a
colon as a delimiter in the following format:
groupId:artifactId:packaging:version. In the above
pom.xml file for our current project, its
coordinate is represented as
mavenbook:my-app:jar:1.0-SNAPSHOT. This notation also
applies to project dependencies, our project relies on JUnit version
3.8.1, it contains a dependency on
junit:junit:jar:3.8.1.
groupIdThe group, company, team, organization, project, or other
group. The convention for group identifiers is that they begin
with the reverse domain name of the organization which creates the
project. Projects from Sonatype would have a
groupId which begins with
org.sonatype, and projects in the Apache
Software Foundation would have a groupId which starts with
org.apache.
artifactIdA unique identifier under groupId which
represents a single project.
versionA specific release of a project. Projects that have been released have a fixed version identifier which refers to a specific version of the project. Projects undergoing active development can use a special identifier which marks a version as a "SNAPSHOT".
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 groupId:artifactId:version
make that project unique; you can't have a project with the same three
groupId, artifactId, and
version identifiers.
packagingThe type of project, defaulting to jar,
describing the packaged output produced by a project. A project
with packaging jar produces a
JAR archive, a project with packaging
war produces a web application.
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 one must do is to 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
triggers the resources:resource goal. In Maven,
artifacts and plugins are retrieved from a remote repository when they
are needed. One of the reasons the initial Maven download is so small
(1.5 MiB) is due to the fact that Maven doesn't ship with much in the
way of plugins. Maven ships with the bare minimum and fetches from a
remote repository when it needs to. Maven ships with a default remote
repository location (http://repo1.maven.org/maven2)
which it uses to download the core Maven plugins and
dependencies.
Often you will be writing a project which depends on libraries with 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? The Maven
repository is defined by structure, a repository is a collection of
project artifacts stored in a structure and format which can be easily
understood by Maven. In a Maven repository everything is 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 repository at http://repo1.maven.org/maven2/.
You will see that an artifact with the coordinates
org.apache.commons:commons-email:1.1 is available
under the directory
/org/apache/commons/commons-email/1.1/ in a file
named commons-email-1.1.jar. The standard for a
Maven repository is to store an artifact in the following directory
relative to the root of the repository:
/<groupId>/<artifactId>/<version>/<artifactId>-<version>.<packaging>
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
C:\Documents and Settings\USERNAME\.m2\repository,
and on Windows Vista, your local repository is in
C:\Users\USERNAME\.m2\repository. On Unix systems,
your local Maven repository is available in
~/.m2/repository. When you build a project like the
simple project you created in the previous section, the
install phase executes a goal which installs your
project's artifacts in your local Maven repository.
In your local repository, you should be able to see the artifact created by our simple project. If you run the mvn install command, Maven will install our project's artifact in your local repository. Try it.
$ mvn install
...
[INFO] [install:install]
[INFO] Installing .../simple-1.0-SNAPSHOT.jar to \
~/.m2/repository/org/sonatype/mavenbook/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—junit:junit:3.8.1—to a path
in a Maven repository
/junit/junit/3.8.1/junit-3.8.1.jar. The ability to
locate an artifact in a repository based on Maven coordinates gives us
the ability to define dependencies in a project's
POM. If you examine the simple project's
pom.xml file, you will see that there is a section
which deals with dependencies, and that this section
contains a single dependency—JUnit.
A more complex project would contain more than one dependency, or
it might contain dependencies that depend on other artifacts. This is
one of Maven's most powerful features, support for transitive
dependencies. Let's say your project depends on a library which, in
turn, depends on five or ten other libraries (something like Spring or
Hibernate, for example). Instead of having to track down all of these
dependencies and list them in your pom.xml
explicitly, you can simply depend on the library you are interested in
and Maven will add the dependencies of this library to your project's
dependencies implicitly. Maven will also take care of working out
conflicts between dependencies, and Maven also provides you with the
ability to customize the default behavior and exclude certain transitive
dependencies.
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
~/.m2/repository/junit/junit/3.8.1/. If you have
been following this chapter's examples, there will be a file named
junit-3.8.1.jar and a
junit-3.8.1.pom file in addition to a few checksum
files which Maven uses to verify the authenticity of a downloaded
artifact. Note that Maven doesn't just download the JUnit
JAR file, Maven also downloads a POM file
for the JUnit dependency. The fact that Maven downloads
POM files in addition to artifacts is central to
Maven's support for transitive dependencies.
When you install your project's artifact in the local Maven
repository, you will also notice that Maven publishes a slightly
modified version of the project's pom.xml file in
the same directory as the JAR file. Storing a
POM file in the repository gives other projects
information about this project, most importantly what dependencies it
has. If project B depends on project A, it also depends on project A's
dependencies. When Maven resolves a dependency artifact from a set of
Maven coordinates, it also retrieves the POM, and
consults the dependencies POM to find any transitive
dependences. These transitive dependencies are then added as
dependencies of the current project.
A dependency in Maven isn't just a JAR. It is a POM file which, 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. The following figure shows a possible scenario for transitive dependences.
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 another 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
project's pom.xml contains a single
dependency—junit:junit:jar:3.8.1—with a scope of
test. When a dependency has a scope of
test, this means that it will not be available to the
compile goal of the Compiler plugin. It will only be
added to the classpath for the compiler:testCompile
and surefire:test goals.
When creating a JAR for a project, dependencies
will not be bundled with the generated artifact as they are only used
for compilation. When Maven is used to create a WAR
or an EAR, you can configure Maven to bundle
dependencies with the generated artifact, and you can also configure
Maven to exclude certain dependencies from the WAR
file using the provided scope. The provided scope
tells Maven that a dependency is needed for compilation, but should not
be bundled with the output of a build. The provided
scope comes in handy when you are developing a web application, you'll
need to compile your code against the Servlet specification, but you
don't want to include the Servlet API
JAR in your web application's
WEB-INF/lib directory.
Another important feature of Maven is the ability to generate documentation and reports. In the simple project's directory, execute the following command:
$ mvn site
This will execute the site lifecycle phase.
Unlike the default build lifecycle that manages generation of code,
manipulation of resources, compilation, packaging, et cetera, this
lifecycle is concerned solely with processing site content under the
src/site directories and generating reports. After
this command executes, you should see a project web site in the
target/site directory. Load
target/site/index.html and you should see a basic
shell of a project site. This shell contains some reports under "Project
Reports" in the left-hand navigation menu, and it also contains
information about the project, the dependencies, and developers
associated with the project under "Project Information". The simple
project's web site is mostly empty, since the POM
contains very little information about itself beyond a coordinate, a
name, URL and single test dependency.
On this site, you'll notice that there are some default reports
which are available, there is a report that details the results of the
unit tests. This 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 which examines unit test
coverage, the JXR report which generates
cross-referenced HTML source code listings useful for
code reviews, the PMD report which analyzes source
code for various coding problems, or the JDepend report which analyzes
the dependencies between packages in a codebase. Site reports are
customized by configuring which reports are included in a build via the
pom.xml file.
We have created a simple project, packaged the project into a Jar,
installed that Jar into the Maven repository for use by other projects,
and generated a site with documentation. We accomplished this without
writing a single line of code or touching a single configuration file. We
also took some time to develop some definitions for some of the core
concepts of Maven. In the next chapter, we're going to start customizing
and modifying our project pom.xml file to add some
dependencies and configure some unit tests.
[2] "archetype." The American Heritage® Dictionary of the English Language, Fourth Edition. Houghton Mifflin Company, 2004. Answers.com 20 Jan. 2008.
[3] There is a fifth, seldom-used coordinate named
classifier which we will introduce later in the
book. You can feel free to ignore classifiers for now.

