Maven: The Reference Maven Guide
Maven_the_reference_guide
Maven_the_reference_guide
Maven_the_reference_guide
Maven_the_reference_guide
Maven_the_reference_guide
User Manual: Pdf
Open the PDF directly: View PDF .
Page Count: 339 [warning: Documents this large are best viewed by clicking the View PDF Link!]
- Introducing Apache Maven
- Installing Maven
- The Project Object Model
- The Build Lifecycle
- Build Profiles
- Running Maven
- Maven Command Line Options
- Defining Properties
- Getting Help
- Using Build Profiles
- Displaying Version Information
- Running in Offline Mode
- Using a Custom POM or Custom Settings File
- Encrypting Passwords
- Dealing with Failure
- Controlling Maven's Verbosity
- Running Maven in Batch Mode
- Downloading and Verifying Dependencies
- Non-recursive Builds
- Using Advanced Reactor Options
- Using the Maven Help Plugin
- Maven Command Line Options
- Maven Configuration
- Maven Assemblies
- Introduction
- Assembly Basics
- Overview of the Assembly Descriptor
- The Assembly Descriptor
- Controlling the Contents of an Assembly
- Best Practices
- Summary
- Properties and Resource Filtering
- Site Generation
- Writing Plugins
- Using Maven Archetypes
- Developing with Flexmojos
- Introduction
- Configuring Build Environment for Flexmojos
- Creating a Flex Mojos Project from an Archetype
- The FlexMojos Lifecycle
- FlexMojos Plugin Goals
- FlexMojos Plugin Reports
- Developing and Customizing Flexmojos
- Android Application Development with Maven
- Introduction
- Configuring Build Environment for Android Development
- Getting Started
- Creating New Projects with the Android Maven Archetypes
- Using Add-Ons
- Multi Module Android Projects
- Using external dependencies
- The Custom Lifecycle from the Android Maven Plugin
- Plugin Configuration Parameters
- Device Interaction
- Emulator Interaction
- Other Useful Android Maven Plugin Goals
- Internal Android Maven Plugin Goals
- Testing Android Application Code
- Native Application Builds
- Tips and Tricks
- Appendix: Settings Details
- Appendix: Sun Specification Alternatives
- Creative Commons License

Maven: The Complete Reference i
Maven: The Complete Reference
Ed. 1.0

Maven: The Complete Reference ii
Contents
1 Introducing Apache Maven 1
1.1 Maven. . . What is it? .................................... 1
1.2 Convention Over Configuration ............................... 2
1.3 A Common Interface .................................... 3
1.4 Universal Reuse through Maven Plugins .......................... 3
1.5 Conceptual Model of a "Project" .............................. 4
1.6 Is Maven an alternative to XYZ? .............................. 5
1.7 Comparing Maven with Ant ................................ 6
2 Installing Maven 10
2.1 Verify your Java Installation ................................ 10
2.2 Downloading Maven .................................... 11
2.3 Installing Maven ...................................... 11

Maven: The Complete Reference iii
2.3.1 Installing Maven on Linux, BSD or Mac OSX ................... 12
2.3.2 Installing Maven on Microsoft Windows ...................... 12
2.4 Testing a Maven Installation ................................ 13
2.5 Maven Installation Details ................................. 13
2.5.1 User-specific Configuration and Repository .................... 14
2.5.2 Upgrading a Maven Installation .......................... 15
2.6 Uninstalling Maven ..................................... 15
2.7 Getting Help with Maven .................................. 15
2.8 About the Apache Software License ............................ 16
3 The Project Object Model 18
3.1 Introduction ......................................... 18
3.2 The POM .......................................... 18
3.2.1 The Super POM .................................. 21
3.2.2 The Simplest POM ................................. 25
3.2.3 The Effective POM ................................. 26
3.2.4 Real POMs ..................................... 26
3.3 POM Syntax ......................................... 26
3.3.1 Project Versions .................................. 27

Maven: The Complete Reference iv
3.3.1.1 Version Build Numbers ......................... 27
3.3.1.2 SNAPSHOT Versions .......................... 28
3.3.2 Property References ................................ 28
3.4 Project Dependencies .................................... 30
3.4.1 Dependency Scope ................................. 31
3.4.2 Optional Dependencies ............................... 32
3.4.3 Dependency Version Ranges ............................ 34
3.4.4 Transitive Dependencies .............................. 35
3.4.4.1 Transitive Dependencies and Scope ................... 35
3.4.5 Conflict Resolution ................................. 36
3.5 Project Relationships .................................... 40
3.5.1 More on Coordinates ................................ 40
3.5.2 Project Inheritance ................................. 42
3.6 POM Best Practices ..................................... 44
3.6.1 Grouping Dependencies .............................. 45
3.6.2 Multi-module vs. Inheritance ........................... 47
3.6.2.1 Simple Project .............................. 47
3.6.2.2 Multi-module Enterprise Project .................... 49

Maven: The Complete Reference v
4 The Build Lifecycle 52
4.1 Introduction ......................................... 52
4.1.1 Clean Lifecycle (clean) ............................... 53
4.1.2 Default Lifecycle (default) ............................. 56
4.1.3 Site Lifecycle (site) ................................. 57
4.2 Package-specific Lifecycles ................................. 58
4.2.1 JAR ......................................... 59
4.2.2 POM ........................................ 59
4.2.3 Maven Plugin .................................... 60
4.2.4 EJB ......................................... 60
4.2.5 WAR ........................................ 61
4.2.6 EAR ........................................ 61
4.2.7 Other Packaging Types ............................... 62
4.3 Common Lifecycle Goals .................................. 63
4.3.1 Process Resources ................................. 63
4.3.2 Compile ....................................... 67
4.3.3 Process Test Resources ............................... 68
4.3.4 Test Compile .................................... 68

Maven: The Complete Reference vi
4.3.5 Test ......................................... 69
4.3.6 Install ........................................ 70
4.3.7 Deploy ....................................... 70
5 Build Profiles 71
5.1 What Are They For? .................................... 71
5.1.1 What is Build Portability .............................. 71
5.1.1.1 Non-Portable Builds ........................... 72
5.1.1.2 Environment Portability ......................... 72
5.1.1.3 Organizational (In-House) Portability .................. 72
5.1.1.4 Wide (Universal) Portability ....................... 73
5.1.2 Selecting an Appropriate Level of Portability ................... 73
5.2 Portability through Maven Profiles ............................. 74
5.2.1 Overriding a Project Object Model ......................... 76
5.3 Profile Activation ...................................... 77
5.3.1 Activation Configuration .............................. 79
5.3.2 Activation by the Absence of a Property ...................... 80
5.4 Listing Active Profiles ................................... 81
5.5 Tips and Tricks ....................................... 81

Maven: The Complete Reference vii
5.5.1 Common Environments .............................. 82
5.5.2 Protecting Secrets .................................. 84
5.5.3 Platform Classifiers ................................. 85
5.6 Summary .......................................... 87
6 Running Maven 88
6.1 Maven Command Line Options ............................... 88
6.1.1 Defining Properties ................................. 88
6.1.2 Getting Help .................................... 89
6.1.3 Using Build Profiles ................................ 90
6.1.4 Displaying Version Information .......................... 90
6.1.5 Running in Offline Mode .............................. 91
6.1.6 Using a Custom POM or Custom Settings File .................. 91
6.1.7 Encrypting Passwords ............................... 91
6.1.8 Dealing with Failure ................................ 92
6.1.9 Controlling Maven’s Verbosity ........................... 92
6.1.10 Running Maven in Batch Mode .......................... 93
6.1.11 Downloading and Verifying Dependencies ..................... 93
6.1.12 Non-recursive Builds ................................ 94

Maven: The Complete Reference viii
6.2 Using Advanced Reactor Options .............................. 94
6.2.1 Advanced Reactor Options Example Project .................... 95
6.2.2 Resuming Builds .................................. 97
6.2.3 Specifying a Subset of Projects ........................... 97
6.2.4 Making a Subset of Projects ............................ 98
6.2.5 Making Project Dependents ............................ 98
6.2.6 Resuming a "make" build ............................. 99
6.3 Using the Maven Help Plugin ................................ 99
6.3.1 Describing a Maven Plugin ............................. 100
7 Maven Configuration 103
7.1 Configuring Maven Plugins ................................. 103
7.1.1 Plugin Configuration Parameters .......................... 103
7.1.2 Adding Plugin Dependencies ............................ 107
7.1.3 Setting Global Plugin Parameters ......................... 108
7.1.4 Setting Execution Specific Parameters ....................... 108
7.1.5 Setting Default Command Line Execution Parameters .............. 109
7.1.6 Setting Parameters for Goals Bound to Default Lifecycle ............. 110
8 Maven Assemblies 112

Maven: The Complete Reference ix
8.1 Introduction ......................................... 112
8.2 Assembly Basics ...................................... 113
8.2.1 Predefined Assembly Descriptors ......................... 114
8.2.2 Building an Assembly ............................... 114
8.2.3 Assemblies as Dependencies ............................ 117
8.2.4 Assembling Assemblies via Assembly Dependencies ............... 118
8.3 Overview of the Assembly Descriptor ........................... 122
8.4 The Assembly Descriptor .................................. 123
8.4.1 Property References in Assembly Descriptors ................... 123
8.4.2 Required Assembly Information .......................... 123
8.5 Controlling the Contents of an Assembly .......................... 125
8.5.1 Files Section ................................... 125
8.5.2 FileSets Section ................................ 126
8.5.3 Default Exclusion Patterns for ........................... 128
8.5.4 dependencySets Section ............................ 129
8.5.4.1 Customizing Dependency Output Location ............... 131
8.5.4.2 Interpolation of Properties in Dependency Output ........... 132
8.5.4.3 Including and Excluding Dependencies by Scope ........... 133

Maven: The Complete Reference x
8.5.4.4 Fine Tuning: Dependency Includes and Excludes ........... 135
8.5.4.5 Transitive Dependencies, Project Attachments, and Project . . . . . . 137
8.5.4.6 Advanced Unpacking Options ...................... 138
8.5.4.7 Summarizing Dependency Sets ..................... 140
8.5.5 moduleSets Sections .............................. 140
8.5.5.1 Module Selection ............................ 141
8.5.5.2 Sources Section ............................. 141
8.5.5.3 Interpolation of outputDirectoryMapping in .......... 143
8.5.5.4 Binaries section ............................. 144
8.5.5.5 moduleSets, Parent POMs ...................... 146
8.5.6 Repositories Section ................................ 146
8.5.7 Managing the Assembly’s Root Directory ..................... 147
8.5.8 componentDescriptors and ......................... 148
8.6 Best Practices ........................................ 149
8.6.1 Standard, Reusable Assembly Descriptors ..................... 149
8.6.2 Distribution (Aggregating) Assemblies ...................... 152
8.7 Summary .......................................... 157
9 Properties and Resource Filtering 158

Maven: The Complete Reference xi
9.1 Introduction ......................................... 158
9.2 Maven Properties ...................................... 159
9.2.1 Maven Project Properties .............................. 159
9.2.2 Maven Settings Properties ............................. 161
9.2.3 Environment Variable Properties .......................... 162
9.2.4 Java System Properties ............................... 162
9.2.5 User-defined Properties ............................... 163
9.3 Resource Filtering ...................................... 164
10 Site Generation 168
10.1 Introduction ......................................... 168
10.2 Building a Project Site with Maven ............................. 169
10.3 Customizing the Site Descriptor .............................. 171
10.3.1 Customizing the Header Graphics ......................... 173
10.3.2 Customizing the Navigation Menu ......................... 173
10.4 Site Directory Structure ................................... 175
10.5 Writing Project Documentation ............................... 176
10.5.1 APT Example .................................... 176
10.5.2 FML Example ................................... 177

Maven: The Complete Reference xii
10.6 Deploying Your Project Website .............................. 178
10.6.1 Configuring Server Authentication ......................... 179
10.6.2 Configuring File and Directory Modes ....................... 179
10.7 Customizing Site Appearance ................................ 180
10.7.1 Customizing the Site CSS ............................. 180
10.7.2 Create a Custom Site Template ........................... 181
10.7.3 Reusable Website Skins .............................. 186
10.7.4 Creating a Custom Theme CSS .......................... 187
10.8 Tips and Tricks ....................................... 189
10.8.1 Inject XHTML into HEAD ............................. 189
10.8.2 Add Links under Your Site Logo .......................... 190
10.8.3 Add Breadcrumbs to Your Site ........................... 190
10.8.4 Add the Project Version .............................. 191
10.8.5 Modify the Publication Date Format and Location ................ 192
10.8.6 Using Doxia Macros ................................ 193
11 Writing Plugins 195
11.1 Introduction ......................................... 195
11.2 Programming Maven .................................... 195

Maven: The Complete Reference xiii
11.2.1 What is Inversion of Control? ........................... 196
11.2.2 Introduction to Plexus ............................... 197
11.2.3 Why Plexus? .................................... 198
11.2.4 What is a Plugin? .................................. 198
11.3 Plugin Descriptor ...................................... 199
11.3.1 Top-level Plugin Descriptor Elements ....................... 201
11.3.2 Mojo Configuration ................................. 202
11.3.3 Plugin Dependencies ................................ 204
11.4 Writing a Custom Plugin .................................. 204
11.4.1 Creating a Plugin Project .............................. 205
11.4.2 A Simple Java Mojo ................................ 206
11.4.3 Configuring a Plugin Prefix ............................ 208
11.4.4 Logging from a Plugin ............................... 211
11.4.5 Mojo Class Annotations .............................. 211
11.4.6 When a Mojo Fails ................................. 213
11.5 Mojo Parameters ...................................... 214
11.5.1 Supplying Values for Mojo Parameters ...................... 214
11.5.2 Multi-valued Mojo Parameters ........................... 216

Maven: The Complete Reference xiv
11.5.3 Depending on Plexus Components ......................... 218
11.5.4 Mojo Parameter Annotations ............................ 219
11.6 Plugins and the Maven Lifecycle .............................. 220
11.6.1 Executing a Parallel Lifecycle ........................... 220
11.6.2 Creating a Custom Lifecycle ............................ 221
11.6.3 Overriding the Default Lifecycle .......................... 223
12 Using Maven Archetypes 225
12.1 Introduction to Maven Archetypes ............................. 225
12.2 Using Archetypes ...................................... 225
12.2.1 Using an Archetype from the Command Line ................... 226
12.2.2 Using the Interactive generate Goal ........................ 227
12.2.3 Using an Archetype from m2eclipse ........................ 229
12.3 Available Archetypes .................................... 229
12.3.1 Common Maven Archetypes ............................ 230
12.3.1.1 maven-archetype-quickstart ....................... 230
12.3.1.2 maven-archetype-webapp ........................ 230
12.3.1.3 maven-archetype-mojo ......................... 230
12.3.2 Notable Third-Party Archetypes .......................... 231

Maven: The Complete Reference xv
12.3.2.1 AppFuse ................................. 231
12.3.2.2 Confluence and JIRA plugins ...................... 232
12.3.2.3 Wicket .................................. 233
12.4 Publishing Archetypes ................................... 234
13 Developing with Flexmojos 237
13.1 Introduction ......................................... 237
13.2 Configuring Build Environment for Flexmojos ....................... 237
13.2.1 Referencing a Repository with the Flex Framework ................ 238
13.2.1.1 Referencing Sonatype’s Flexmojos Repository in a POM . . . . . . . 238
13.2.1.2 Proxying Sonatype’s Flexmojos Repository with Nexus ........ 239
13.2.2 Configure a Flexmojos Proxy Repository in Nexus ................ 239
13.2.2.1 Add the Flexmojos Proxy Repository to a Group ............ 242
13.2.2.2 Configure Your Development Environment for Nexus ......... 244
13.2.3 Configuring Environment to Support Flex Unit Tests ............... 245
13.2.4 Adding FlexMojos to Your Maven Settings’ Plugin Groups ............ 246
13.3 Creating a Flex Mojos Project from an Archetype ..................... 247
13.3.1 Creating a Flex Library ............................... 247
13.3.2 Creating a Flex Application ............................ 254

Maven: The Complete Reference xvi
13.3.3 Creating a Multi-module Project: Web Application with a Flex .......... 258
13.4 The FlexMojos Lifecycle .................................. 267
13.4.1 The SWC Lifecycle ................................. 268
13.4.2 The SWF Lifecycle ................................. 269
13.5 FlexMojos Plugin Goals .................................. 271
13.5.1 Generating Actionscript Documentation ...................... 272
13.5.2 Compiling Flex Source ............................... 272
13.5.3 Generating Flex Builder Project Files ....................... 273
13.6 FlexMojos Plugin Reports ................................. 274
13.6.1 Generating Actionscript Documentation Report .................. 274
13.7 Developing and Customizing Flexmojos .......................... 276
13.7.1 Get the Flexmojos Source Code .......................... 276
14 Android Application Development with Maven 278
14.1 Introduction ......................................... 278
14.2 Configuring Build Environment for Android Development ................ 279
14.2.1 Installing the Android SDK ............................ 279
14.2.2 Android artifact install into Maven repository ................... 280
14.2.2.1 Installation to local repository ...................... 280

Maven: The Complete Reference xvii
14.2.2.2 Installation to remote repository ..................... 281
14.2.2.3 Installation of a subset of all platforms ................. 281
14.3 Getting Started ....................................... 282
14.4 Creating New Projects with the Android Maven Archetypes ................ 284
14.5 Using Add-Ons ....................................... 285
14.6 Multi Module Android Projects ............................... 286
14.7 Using external dependencies ................................ 286
14.8 The Custom Lifecycle from the Android Maven Plugin .................. 287
14.9 Plugin Configuration Parameters .............................. 288
14.10Device Interaction ...................................... 289
14.11Emulator Interaction .................................... 290
14.12Other Useful Android Maven Plugin Goals ........................ 291
14.12.1 Manifest-update .................................. 291
14.12.2 Zipalign ....................................... 291
14.12.3 Help ......................................... 291
14.13Internal Android Maven Plugin Goals ........................... 291
14.14Testing Android Application Code ............................. 292
14.14.1 Unit tests ...................................... 293

Maven: The Complete Reference xviii
14.14.2 Instrumentation tests ................................ 293
14.15Native Application Builds ................................. 294
14.16Tips and Tricks ....................................... 294
14.16.1 Other Maven Plugins ................................ 294
14.16.2 Performing a Release Build ............................ 295
14.16.3 Configuring command line usage ......................... 295
15 Appendix: Settings Details 296
15.1 Quick Overview ....................................... 296
15.2 Settings Details ....................................... 297
15.2.1 Simple Values ................................... 297
15.2.2 Servers ....................................... 298
15.2.3 Mirrors ....................................... 299
15.2.4 Proxies ....................................... 300
15.2.5 Profiles ....................................... 301
15.2.6 Activation ...................................... 301
15.2.7 Properties ...................................... 303
15.2.8 Repositories .................................... 304
15.2.9 Plugin Repositories ................................. 305

Maven: The Complete Reference xx
Preface
Maven is a build tool, a project management tool, an abstract container for running build tasks. It is a
tool that has shown itself indispensable for projects that graduate beyond the simple and need to start
finding consistent ways to manage and build large collections of interdependent modules and libraries
which make use of tens or hundreds of third-party components. It is a tool that has removed much of the
burden of 3rd party dependency management from the daily work schedule of millions of engineers, and
it has enabled many organizations to evolve beyond the toil and struggle of build management into a new
phase where the effort required to build and maintain software is no longer a limiting factor in software
design.
This work is the first attempt at a comprehensive title on Maven. It builds upon the combined experience
and work of the authors of all previous Maven titles, and you should view it not as a finished work but
as the first edition in a long line of updates to follow. While Maven has been around for a few years,
the authors of this book believe that it has just begun to deliver on the audacious promises it makes. The
authors, and company behind this book, Sonatype, believe that the publishing of this book marks the
beginning of a new phase of innovation and development surrounding Maven and the software ecosystem
that surrounds it.
Acknowledgements
Sonatype would like to thank the following contributors. The people listed below have provided feedback
which has helped improve the quality of this book. Thanks to Raymond Toal, Steve Daly, Paul Strack, Paul
Reinerfelt, Chad Gorshing, Marcus Biel, Brian Dols, Mangalaganesh Balasubramanian, Marius Kruger,
and Mark Stewart. Special thanks to Joel Costigliola for helping to debug and correct the Spring web
chapter. Stan Guillory was practically a contributing author given the number of corrections he posted to
the book’s Get Satisfaction. Thank you Stan. Special thanks to Richard Coasby of Bamboo for acting as
the provisional grammar consultant.

Maven: The Complete Reference xxi
Thanks to our contributing authors including Eric Redmond.
Thanks to the following contributors who reported errors either in an email or using the Get Satisfaction
site: Paco Soberón, Ray Krueger, Steinar Cook, Henning Saul, Anders Hammar, "george_007", "ksan-
gani", Niko Mahle, Arun Kumar, Harold Shinsato, "mimil", "-thrawn-", Matt Gumbley. If you see your
Get Satisfaction username in this list, and you would like it replaced with your real name, send an email
to book@sonatype.com.
Special thanks to Grant Birchmeier for taking the time to proofread portions of the book and file extremely
detailed feedback via GetSatisfaction.

Maven: The Complete Reference xxii
Copyright
Copyright © 2008-2011 Sonatype, Inc.
Online version published by Sonatype, Inc.
This work is licensed under a Creative Commons Attribution-Noncommercial-No Derivative Works 3.0
United States license. For more information about this license, see creativecommons.org/licenses/by-nc-
nd/3.0/us/.
Nexus™, Nexus Professional™, and all Nexus-related logos are trademarks or registered trademarks of
Sonatype, Inc., in the United States and other countries.
Java™ and all Java-based trademarks and logos are trademarks or registered trademarks of Sun Microsys-
tems, Inc., in the United States and other countries.
IBM® and WebSphere® are trademarks or registered trademarks of International Business Machines,
Inc., in the United States and other countries.
Eclipse™ is a trademark of the Eclipse Foundation, Inc., in the United States and other countries.
Apache and the Apache feather logo are trademarks of The Apache Software Foundation.
Linux® is the registered trademark of Linus Torvalds in the U.S. and other countries.
Many of the designations used by manufacturers and sellers to distinguish their products are claimed as
trademarks. Where those designations appear in this book, and Sonatype, Inc. was aware of a trademark
claim, the designations have been printed in caps or initial caps.

Maven: The Complete Reference xxiii
While every precaution has been taken in the preparation of this book, the publisher and authors assume no
responsibility for errors or omissions, or for damages resulting from the use of the information contained
herein.

Maven: The Complete Reference 1 / 316
Chapter 1
Introducing Apache Maven
Although there are a number of references for Maven online, there is no single, well-written narrative for
introducing Maven that can serve as both an authoritative reference and an introduction. What we’ve tried
to do with this effort is provide such a narrative coupled with useful reference material.
1.1 Maven. . . What is it?
The answer to this question depends on your own perspective. The great majority of Maven users are
going to call Maven a “build tool”: a tool used to build deployable artifacts from source code. Build
engineers and project managers might refer to Maven as something more comprehensive: a project man-
agement tool. What is the difference? A build tool such as Ant is focused solely on preprocessing,
compilation, packaging, testing, and distribution. A project management tool such as Maven provides a
superset of features found in a build tool. In addition to providing build capabilities, Maven can also run
reports, generate a web site, and facilitate communication among members of a working team.
A more formal definition of Apache Maven: Maven is a project management tool which encompasses
a project object model, a set of standards, a project lifecycle, a dependency management system, and
logic for executing plugin goals at defined phases in a lifecycle. When you use Maven, you describe your
project using a well-defined project object model, Maven can then apply cross-cutting logic from a set of
shared (or custom) plugins.
Don’t let the fact that Maven is a "project management" tool scare you away. If you were just looking

Maven: The Complete Reference 2 / 316
for a build tool, Maven will do the job. In fact, the first few chapters of this book will deal with the most
common use case: using Maven to build and distribute your project.
1.2 Convention Over Configuration
Convention over configuration is a simple concept. Systems, libraries, and frameworks should assume
reasonable defaults. Without requiring unnecessary configuration, systems should "just work". Popular
frameworks such as Ruby on Rails and EJB3 have started to adhere to these principles in reaction to
the configuration complexity of frameworks such as the initial EJB 2.1 specifications. An illustration of
convention over configuration is something like EJB3 persistence: all you need to do to make a particular
bean persistent is to annotate that class with @Entity. The framework assumes table and column names
based on the name of the class and the names of the properties. Hooks are provided for you to override
these default, assumed names if the need arises, but, in most cases, you will find that using the framework-
supplied defaults results in a faster project execution.
Maven incorporates this concept by providing sensible default behavior for projects. Without customiza-
tion, source code is assumed to be in ${basedir}/src/main/java and resources are assumed to be in
${basedir}/src/main/resources. Tests are assumed to be in ${basedir}/src/test, and a project is assumed
to produce a JAR file. Maven assumes that you want the compile byte code to ${basedir}/target/classes
and then create a distributable JAR file in ${basedir}/target. While this might seem trivial, consider the
fact that most Ant-based builds have to define the locations of these directories. Ant doesn’t ship with any
built-in idea of where source code or resources might be in a project; you have to supply this informa-
tion. Maven’s adoption of convention over configuration goes farther than just simple directory locations,
Maven’s core plugins apply a common set of conventions for compiling source code, packaging distri-
butions, generating web sites, and many other processes. Maven’s strength comes from the fact that it is
"opinionated", it has a defined life-cycle and a set of common plugins that know how to build and assem-
ble software. If you follow the conventions, Maven will require almost zero effort - just put your source
in the correct directory, and Maven will take care of the rest.
One side-effect of using systems that follow "convention over configuration" is that end-users might feel
that they are forced to use a particular methodology or approach. While it is certainly true that Maven has
some core opinions that shouldn’t be challenged, most of the defaults can be customized. For example,
the location of a project’s source code and resources can be customized, names of JAR files can be
customized, and through the development of custom plugins, almost any behavior can be tailored to your
specific environment’s requirements. If you don’t care to follow convention, Maven will allow you to
customize defaults in order to adapt to your specific requirements.

Maven: The Complete Reference 3 / 316
1.3 A Common Interface
Before Maven provided a common interface for building software, every single project had someone ded-
icated to managing a fully customized build system. Developers had to take time away from developing
software to learn about the idiosyncrasies of each new project they wanted to contribute to. In 2001,
you’d have a completely different approach to building a project like Turbine than you would to building
a project like Tomcat. If a new source code analysis tool came out that would perform static analysis on
source code, or if someone developed a new unit testing framework, everybody would have to drop what
they were doing and figure out how to fit it into each project’s custom build environment. How do you run
unit tests? There were a thousand different answers. This environment was characterized by a thousand
endless arguments about tools and build procedures. The age before Maven was an age of inefficiency,
the age of the "Build Engineer".
Today, most open source developers have used or are currently using Maven to manage new software
projects. This transition is less about developers moving from one build tool to another and more about
developers starting to adopt a common interface for project builds. As software systems have become
more modular, build systems have become more complex, and the number of projects has sky-rocketed.
Before Maven, when you wanted to check out a project like Apache ActiveMQ or Apache ServiceMix
from Subversion and build it from source, you really had to set aside about an hour to figure out the
build system for each particular project. What does the project need to build? What libraries do I need to
download? Where do I put them? What goals can I execute in the build? In the best case, it took a few
minutes to figure out a new project’s build, and in the worst cases (like the old Servlet API implementation
in the Jakarta Project), a project’s build was so difficult it would take multiple hours just to get to the point
where a new contributor could edit source and compile the project. These days, you check it out from
source, and you run mvn install.
While Maven provides an array of benefits including dependency management and reuse of common build
logic through plugins, the core reason why it has succeeded is that it has defined a common interface for
building software. When you see that a project like Apache ActiveMQ uses Maven, you can assume that
you’ll be able to check it out from source and build it with mvn install without much hassle. You
know where the ignition keys goes, you know that the gas pedal is on the right-side, and the brake is on
the left.
1.4 Universal Reuse through Maven Plugins
The core of Maven is pretty dumb, it doesn’t know how to do much beyond parsing a few XML doc-
uments and keeping track of a lifecycle and a few plugins. Maven has been designed to delegate most
responsibility to a set of Maven Plugins which can affect the Maven Lifecycle and offer access to goals.
Most of the action in Maven happens in plugin goals which take care of things like compiling source,

Maven: The Complete Reference 4 / 316
packaging bytecode, publishing sites, and any other task which need to happen in a build. The Maven
you download from Apache doesn’t know much about packaging a WAR file or running JUnit tests; most
of the intelligence of Maven is implemented in the plugins and the plugins are retrieved from the Maven
Repository. In fact, the first time you ran something like mvn install with a brand-new Maven in-
stallation it retrieved most of the core Maven plugins from the Central Maven Repository. This is more
than just a trick to minimize the download size of the Maven distribution, this is behavior which allows
you to upgrade a plugin to add capability to your project’s build. The fact that Maven retrieves both
dependencies and plugins from the remote repository allows for universal reuse of build logic.
The Maven Surefire plugin is the plugin that is responsible for running unit tests. Somewhere between
version 1.0 and the version that is in wide use today someone decided to add support for the TestNG unit
testing framework in addition to the support for JUnit. This upgrade happened in a way that didn’t break
backwards compatibility. If you were using the Surefire plugin to compile and execute JUnit 3 unit tests,
and you upgraded to the most recent version of the Surefire plugin, your tests continued to execute without
fail. But, you gained new functionality, if you want to execute unit tests in TestNG you now have that
ability. You also gained the ability to run annotated JUnit 4 unit tests. You gained all of these capabilities
without having to upgrade your Maven installation or install new software. Most importantly, nothing
about your project had to change aside from a version number for a plugin a single Maven configuration
file called the Project Object Model (POM).
It is this mechanism that affects much more than the Surefire plugin. Maven has plugins for everything
from compiling Java code, to generating reports, to deploying to an application server. Maven has ab-
stracted common build tasks into plugins which are maintained centrally and shared universally. If the
state-of-the-art changes in any area of the build, if some new unit testing framework is released or if some
new tool is made available, you don’t have to be the one to hack your project’s custom build system to
support it. You benefit from the fact that plugins are downloaded from a remote repository and maintained
centrally. This is what is meant by universal reuse through Maven plugins.
1.5 Conceptual Model of a "Project"
Maven maintains a model of a project. You are not just compiling source code into bytecode, you are
developing a description of a software project and assigning a unique set of coordinates to a project. You
are describing the attributes of the project. What is the project’s license? Who develops and contributes
to the project? What other projects does this project depend upon? Maven is more than just a "build tool",
it is more than just an improvement on tools like make and Ant, it is a platform that encompasses a new
semantics related to software projects and software development. This definition of a model for every
project enables such features as:
Dependency Management

Maven: The Complete Reference 5 / 316
Because a project is defined by a unique set of coordinates consisting of a group identifier, an
artifact identifier, and a version, projects can now use these coordinates to declare dependencies.
Remote Repositories
Related to dependency management, we can use the coordinates defined in the Maven Project
Object Model (POM) to create repositories of Maven artifacts.
Universal Reuse of Build Logic
Plugins contain logic that works with the descriptive data and configuration parameters defined
in Project Object Model (POM); they are not designed to operate upon specific files in known
locations.
Tool Portability / Integration
Tools like Eclipse, NetBeans, and IntelliJ now have a common place to find information about a
project. Before the advent of Maven, every IDE had a different way to store what was essentially
a custom Project Object Model (POM). Maven has standardized this description, and while each
IDE continues to maintain custom project files, they can be easily generated from the model.
Easy Searching and Filtering of Project Artifacts
Tools like Nexus allow you to index and search the contents of a repository using the information
stored in the POM.
1.6 Is Maven an alternative to XYZ?
So, sure, Maven is an alternative to Ant, but Apache Ant continues to be a great, widely-used tool. It
has been the reigning champion of Java builds for years, and you can integrate Ant build scripts with
your project’s Maven build very easily. This is a common usage pattern for a Maven project. On the
other hand, as more and more open source projects move to Maven as a project management platform,
working developers are starting to realize that Maven not only simplifies the task of build management, it
is helping to encourage a common interface between developers and software projects. Maven is more of
a platform than a tool, while you could consider Maven an alternative to Ant, you are comparing apples
to oranges. "Maven" includes more than just a build tool.
This is the central point that makes all of the Maven vs. Ant, Maven vs. Buildr, Maven vs. Gradle
arguments irrelevant. Maven isn’t totally defined by the mechanics of your build system. It isn’t about
scripting the various tasks in your build as much as it is about encouraging a set of standards, a common
interface, a life-cycle, a standard repository format, a standard directory layout, etc. It certainly isn’t
about what format the POM happens to be in (XML vs. YAML vs. Ruby). Maven is much larger than
that, and Maven refers to much more than the tool itself. When this book talks of Maven, it is referring to
the constellation of software, systems, and standards that support it. Buildr, Ivy, Gradle, all of these tools
interact with the repository format that Maven helped create, and you could just as easily use a repository
manager like Nexus to support a build written entirely in Ant.

Maven: The Complete Reference 6 / 316
While Maven is an alternative to many of these tools, the community needs to evolve beyond seeing
technology as a zero-sum game between unfriendly competitors in a competition for users and developers.
This might be how large corporations relate to one another, but it has very little relevance to the way that
open source communities work. The headline "Who’s winning? Ant or Maven?" isn’t very constructive.
If you force us to answer this question, we’re definitely going to say that Maven is a superior alternative
to Ant as a foundational technology for a build; at the same time, Maven’s boundaries are constantly
shifting and the Maven community is constantly trying to seek out new ways to become more ecumenical,
more inter-operable, more cooperative. The core tenets of Maven are declarative builds, dependency
management, repository managers, universal reuse through plugins, but the specific incarnation of these
ideas at any given moment is less important than the sense that the open source community is collaborating
to reduce the inefficiency of "enterprise-scale builds".
1.7 Comparing Maven with Ant
The authors of this book have no interest in creating a feud between Apache Ant and Apache Maven,
but we are also cognizant of the fact that most organizations have to make a decision between the two
standard solutions: Apache Ant and Apache Maven. In this section, we compare and contrast the tools.
Ant excels at build process, it is a build system modeled after make with targets and dependencies. Each
target consists of a set of instructions which are coded in XML. There is a copy task and a javac task
as well as a jar task. When you use Ant, you supply Ant with specific instructions for compiling and
packaging your output. Look at the following example of a simple build.xml file:
A Simple Ant build.xml file
<project name="my-project" default="dist" basedir=".">
<description>
simple example build file
</description>
<!-- set global properties for this build -->
<property name="src" location="src/main/java"/>
<property name="build" location="target/classes"/>
<property name="dist" location="target"/>
<target name="init">
<!-- Create the time stamp -->
<tstamp/>
<!-- Create the build directory structure used by compile -->
<mkdir dir="${build}"/>
</target>
<target name="compile" depends="init"

Maven: The Complete Reference 7 / 316
description="compile the source " >
<!-- Compile the java code from ${src} into ${build} -->
<javac srcdir="${src}" destdir="${build}"/>
</target>
<target name="dist" depends="compile"
description="generate the distribution" >
<!-- Create the distribution directory -->
<mkdir dir="${dist}/lib"/>
<!-- Put everything in ${build} into the MyProject-${DSTAMP}.jar ←-
file -->
<jar jarfile="${dist}/lib/MyProject-${DSTAMP}.jar" basedir="${ ←-
build}"/>
</target>
<target name="clean"
description="clean up" >
<!-- Delete the ${build} and ${dist} directory trees -->
<delete dir="${build}"/>
<delete dir="${dist}"/>
</target>
</project>
In this simple Ant example, you can see how you have to tell Ant exactly what to do. There is a com-
pile goal which includes the javac task that compiles the source in the src/main/java directory to the
target/classes directory. You have to tell Ant exactly where your source is, where you want the resulting
bytecode to be stored, and how to package this all into a JAR file. While there are some recent develop-
ments that help make Ant less procedural, a developer’s experience with Ant is in coding a procedural
language written in XML.
Contrast the previous Ant example with a Maven example. In Maven, to create a JAR file from some Java
source, all you need to do is create a simple pom.xml, place your source code in ${basedir}/src/main/java
and then run mvn install from the command line. The example Maven pom.xml that achieves the
same results as the simple Ant file listed in A Simple Ant build.xml file is shown in A Sample Maven
pom.xml.
A Sample Maven pom.xml
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>org.sonatype.mavenbook</groupId>
<artifactId>my-project</artifactId>
<version>1.0</version>
</project>

Maven: The Complete Reference 8 / 316
That’s all you need in your pom.xml. Running mvn install from the command line will process
resources, compile source, execute unit tests, create a JAR, and install the JAR in a local repository for
reuse in other projects. Without modification, you can run mvn site and then find an index.html file in
target/site that contains links to JavaDoc and a few reports about your source code.
Admittedly, this is the simplest possible example project containing nothing more than some source code
and producing a simple JAR. It is a project which closely follows Maven conventions and doesn’t require
any dependencies or customization. If we wanted to start customizing the behavior, our pom.xml is going
to grow in size, and in the largest of projects you can see collections of very complex Maven POMs which
contain a great deal of plugin customization and dependency declarations. But, even when your project’s
POM files become more substantial, they hold an entirely different kind of information from the build file
of a similarly sized project using Ant. Maven POMs contain declarations: "This is a JAR project", and
"The source code is in src/main/java". Ant build files contain explicit instructions: "This is project", "The
source is in src/main/java", "Run javac against this directory", "Put the results in target/classes", "Create
a JAR from the . . . .", etc. Where Ant had to be explicit about the process, there was something "built-in"
to Maven that just knew where the source code was and how it should be processed.
The differences between Ant and Maven in this example are:
• Apache Ant
–Ant doesn’t have formal conventions like a common project directory structure or default behav-
ior. You have to tell Ant exactly where to find the source and where to put the output. Informal
conventions have emerged over time, but they haven’t been codified into the product.
–Ant is procedural. You have to tell Ant exactly what to do and when to do it. You have to tell it to
compile, then copy, then compress.
–Ant doesn’t have a lifecycle. You have to define goals and goal dependencies. You have to attach a
sequence of tasks to each goal manually.
• Apache Maven
–Maven has conventions. It knows where your source code is because you followed the convention.
Maven’s Compiler plugin put the bytecode in target/classes, and it produces a JAR file in target.
–Maven is declarative. All you had to do was create a pom.xml file and put your source in the default
directory. Maven took care of the rest.
–Maven has a lifecycle which was invoked when you executed mvn install. This command told
Maven to execute a series of sequential lifecycle phases until it reached the install lifecycle phase. As
a side-effect of this journey through the lifecycle, Maven executed a number of default plugin goals
which did things like compile and create a JAR.
Maven has built-in intelligence about common project tasks in the form of Maven plugins. If you wanted
to write and execute unit tests, all you would need to do is write the tests, place them in ${basedir}/src/test/java,

Maven: The Complete Reference 9 / 316
add a test-scoped dependency on either TestNG or JUnit, and run mvn test. If you wanted to deploy a
web application and not a JAR, all you would need to do is change your project type to war and put your
docroot in ${basedir}/src/main/webapp. Sure, you can do all of this with Ant, but you will be writing
the instructions from scratch. In Ant, you would first have to figure out where the JUnit JAR file should
be. Then you would have to create a classpath that includes the JUnit JAR file. Then you would tell
Ant where it should look for test source code, write a goal that compiles the test source to bytecode, and
execute the unit tests with JUnit.
Without supporting technologies like antlibs and Ivy (even with these supporting technologies), Ant has
the feeling of a c`ustom procedural build. An efficient set of Maven POMs in a project which adheres
to Maven’s assumed conventions has surprisingly little XML compared to the Ant alternative. Another
benefit of Maven is the reliance on widely-shared Maven plugins. Everyone uses the Maven Surefire
plugin for unit testing, and if someone adds support for a new unit testing framework, you can gain new
capabilities in your own build by just incrementing the version of a particular Maven plugin in your
project’s POM.
The decision to use Maven or Ant isn’t a binary one, and Ant still has a place in a complex build. If
your current build contains some highly customized process, or if you’ve written some Ant scripts to
complete a specific process in a specific way that cannot be adapted to the Maven standards, you can still
use these scripts with Maven. Ant is made available as a core Maven plugin. Custom Maven plugins can
be implemented in Ant, and Maven projects can be configured to execute Ant scripts within the Maven
project lifecycle.

Maven: The Complete Reference 10 / 316
Chapter 2
Installing Maven
This chapter contains very detailed instructions for installing Maven on a number of different platforms.
Instead of assuming a level of familiarity with installing software and setting environment variables, we’ve
opted to be as thorough as possible to minimize any problems that might arise due to a partial installation.
The only thing this chapter assumes is that you’ve already installed a suitable Java Development Kit
(JDK). If you are just interested in installation, you can move on to the rest of the book after reading
through Section 2.2 and Section 2.3. If you are interested in the details of your Maven installation, this
entire chapter will give you an overview of what you’ve installed and the meaning of the Apache Software
License, Version 2.0.
2.1 Verify your Java Installation
The latest version of Maven currently requires the usage of Java 7 or higher. While older Maven versions
can run on older Java versions, this book assumes that you are running at least Java 7. Go with the most
recent stable Java Development Kit (JDK) available for your operating system.
% java -version
java version "1.7.0_71"
Java(TM) SE Runtime Environment (build 1.7.0_71-b14)
Java HotSpot(TM) 64-Bit Server VM (build 24.71-b01, mixed mode)

Maven: The Complete Reference 11 / 316
Tip
More details about Java version required for different Maven versions can be found on theMaven site.
Maven works with all certified JavaTM compatible development kits, and a few non-certified implemen-
tations of Java. The examples in this book were written and tested against the official Java Development
Kit releases downloaded from the Oracle web site.
2.2 Downloading Maven
You can download Maven from the Apache Maven project website at http://maven.apache.org/download.html.
When downloading Maven, you can download the latest available version the latest available version of
Maven 3 in various branches. The latest version of Maven 3 when this book was last updated was Maven
3.3.3. If you are not familiar with the Apache Software License, you should familiarize yourself with the
terms of the license before you start using the product. More information on the Apache Software License
can be found in Section 2.8.
Tip
We recommend to avoid Maven 2 as it is no longer maintained and use the latest version of Maven 3
available and listed as the current stable version.
To download Maven , go to http://maven.apache.org/download.html and select the appropriate binary
archive format for your platform. The contents of the zip or tar.gz are the same.
2.3 Installing Maven
There are wide differences between operating systems such as Mac OS X and Microsoft Windows, and
there are subtle differences between different versions of Windows. Luckily, the process of installing
Maven on all of these operating systems is relatively painless and straightforward. The following sections
outline the recommended best-practice for installing Maven on a variety of operating systems.

Maven: The Complete Reference 12 / 316
2.3.1 Installing Maven on Linux, BSD or Mac OSX
You can download a binary release of Maven from http://maven.apache.org/download.html. Download
the current release of Maven in a format that is convenient for you to work with. Pick an appropriate place
for it to live, and expand the archive there. If you expanded the archive into the directory /opt/apache-
maven-3.2.5, you may want to create a symbolic link to make it easier to work with and to avoid the need
to change any environment configuration when you upgrade to a newer version:
$ cd /opt
$ ln -s apache-maven-3.2.5 maven
$ export PATH=/opt/maven/bin:${PATH}
Once Maven is installed, you need to do a couple of things to make it work correctly. You need to add its
bin directory in the distribution (in this example, /opt/maven/bin) to your command path.
You’ll need to add PATH to a script that will run every time you login. To do this, add the following lines
to .bash_login or .profile
export PATH=/opt/maven/bin:${PATH}
Once you’ve added these lines to your own environment, you will be able to run Maven from the command
line.
Note
These installation instructions assume that you are running bash.
2.3.2 Installing Maven on Microsoft Windows
Installing Maven on Windows is very similar to installing Maven on Mac OSX, the main differences being
the installation location and the setting of an environment variable. This book assumes a Maven instal-
lation directory of c:\Program Files\apache-maven-3.2.5, but it won’t make a difference if
you install Maven in another directory as long as you configure the proper environment variables. Once
you’ve unpacked Maven to the installation directory, you will need to set the PATH environment variable.
You can use the following commands:
C:\Users\tobrien > set PATH=%PATH%;"c:\Program Files\apache-maven-3.2.5\ ←-
bin"

Maven: The Complete Reference 13 / 316
Setting these environment variables on the command-line will allow you to run Maven in your current
session, but unless you add them to the System environment variables through the control panel, you’ll
have to execute these two lines every time you log into your system. You should modify both of these
variables through the Control Panel in Microsoft Windows.
2.4 Testing a Maven Installation
Once Maven is installed, you can check the version by running mvn -v from the command-line. If
Maven has been installed, you should see something resembling the following output.
$ mvn -v
Apache Maven 3.2.5 (12a6b3acb947671f09b81f49094c53f426d8cea1; 2014-12-14 ←-
T09:29:23-08:00)
Maven home: /opt/apache-maven-3.2.5
Java version: 1.7.0_71, vendor: Oracle Corporation
Java home: /Library/Java/JavaVirtualMachines/jdk1.7.0_71.jdk/Contents/Home ←-
/jre
Default locale: en_US, platform encoding: UTF-8
OS name: "mac os x", version: "10.8.5", arch: "x86_64", family: "mac"
If you see this output, you know that Maven is available and ready to be used. If you do not see this
output, and your operating system cannot find the mvn command, make sure that your PATH environment
variable and M2_HOME environment variable have been properly set.
2.5 Maven Installation Details
Maven’s download measures in at roughly 1.5 MiB, it has attained such a slim download size because
the core of Maven has been designed to retrieve plugins and dependencies from a remote repository on-
demand. When you start using Maven, it will start to download plugins to a local repository described in
Section 2.5.1. In case you are curious, let’s take a quick look at what is in Maven’s installation directory.
$ ls /opt/maven -p1
LICENSE.txt
NOTICE.txt
README.txt
bin/
boot/
conf/
lib/

Maven: The Complete Reference 14 / 316
LICENSE.txt contains the software license for Apache Maven. This license is described in some detail
later in the section Section 2.8.NOTICE.txt contains some notices and attributions required by libraries
that Maven depends on. README.txt contains some installation instructions. bin/ contains the mvn script
that executes Maven. boot/ contains a JAR file (classwords-1.1.jar) that is responsible for creating the
Class Loader in which Maven executes. conf/ contains a global settings.xml that can be used to customize
the behavior of your Maven installation. If you need to customize Maven, it is customary to override any
settings in a settings.xml file stored in ~/.m2.lib/ contains a single JAR file (maven-core-3.0.3-uber.jar)
that contains the core of Maven.
Note
Unless you are working in a shared Unix environment, you should avoid customizing the settings.xml in
M2_HOME/conf. Altering the global settings.xml file in the Maven installation itself is usually unneces-
sary and it tends to complicate the upgrade procedure for Maven as you’ll have to remember to copy the
customized settings.xml from the old Maven installation to the new installation. If you need to customize
settings.xml, you should be editing your own settings.xml in ~/.m2/settings.xml.
2.5.1 User-specific Configuration and Repository
Once you start using Maven extensively, you’ll notice that Maven has created some local user-specific
configuration files and a local repository in your home directory. In ~/.m2 there will be:
~/.m2/settings.xml
A file containing user-specific configuration for authentication, repositories, and other information
to customize the behavior of Maven.
~/.m2/repository/
This directory contains your local Maven repository. When you download a dependency from a
remote Maven repository, Maven stores a copy of the dependency in your local repository.
Note
In Unix (and OSX), your home directory will be referred to using a tilde (i.e. ~/bin refers to /home/to-
brien/bin). In Windows, we will also be using ~to refer to your home directory. In Windows XP, your
home directory is C:\Documents and Settings\tobrien, and in Windows Vista, your home directory is
C:\Users\tobrien. From this point forward, you should translate paths such as ~/m2 to your operating
system’s equivalent.

Maven: The Complete Reference 15 / 316
2.5.2 Upgrading a Maven Installation
If you’ve installed Maven on a Mac OSX or Unix machine according to the details in Section 2.3.1, it
should be easy to upgrade to newer versions of Maven when they become available. Simply install the
newer version of Maven (/opt/maven-3.future) next to the existing version of Maven (/opt/maven-3.2.5).
Then switch the symbolic link /opt/maven from /opt/maven-3.2.5 to /opt/maven-3.future. Since, you’ve
already set your M2_HOME variable to point to /opt/maven, you won’t need to change any environment
variables.
If you have installed Maven on a Windows machine, simply unpack Maven to c:\Program Files\maven-
3.future and update your M2_HOME variable.
Note
If you have any customizations to the global settings.xml in M2_HOME/conf, you will need to copy this
settings.xml to the conf directory of the new Maven installation.
2.6 Uninstalling Maven
Most of the installation instructions involve unpacking of the Maven distribution archive in a directory
and setting of various environment variables. If you need to remove Maven from your computer, all you
need to do is delete your Maven installation directory and remove the environment variables. You will
also want to delete the ~/.m2 directory as it contains your local repository.
2.7 Getting Help with Maven
While this book aims to be a comprehensive reference, there are going to be topics we will miss and
special situations and tips which are not covered. While the core of Maven is very simple, the real work
in Maven happens in the plugins, and there are too many plugins available to cover them all in one book.
You are going to encounter problems and features which have not been covered in this book; in these
cases, we suggest searching for answers at the following locations:
maven.apache.org
This will be the first place to look, the Maven web site contains a wealth of information and doc-

Maven: The Complete Reference 16 / 316
umentation. Every plugin has a few pages of documentation and there are a series of "quick start"
documents which will be helpful in addition to the content of this book. While the Maven site
contains a wealth of information, it can also be a frustrating, confusing, and overwhelming. There
is a custom Google search box on the main Maven page that will search known Maven sites for
information. This provides better results than a generic Google search.
Maven User Mailing List
The Maven User mailing list is the place for users to ask questions. Before you ask a question
on the user mailing list, you will want to search for any previous discussion that might relate
to your question. It is bad form to ask a question that has already been asked without first
checking to see if an answer already exists in the archives. There are a number of useful mail-
ing list archive browsers, we’ve found Nabble to the be the most useful. You can browse the
User mailing list archives here: http://www.nabble.com/Maven---Users-f178.html. You can
join the user mailing list by following the instructions available here http://maven.apache.org/-
mail-lists.html.
www.sonatype.com
Sonatype maintains an online copy of this book and other tutorials related to Apache Maven.
2.8 About the Apache Software License
Apache Maven is released under the Apache Software License, Version 2.0. If you want to read this
license, you can read ${M2_HOME}/LICENSE.txt or read this license on the Open Source Initiative’s
web site here: http://www.opensource.org/licenses/apache2.0.php.
There’s a good chance that, if you are reading this book, you are not a lawyer. If you are wondering
what the Apache License, Version 2.0 means, the Apache Software Foundation has assembled a very
helpful Frequently Asked Questions (FAQ) page about the license available here: http://www.apache.org/-
foundation/licence-FAQ.html. Here’s is the answer to the question "I am not a lawyer. What does it all
mean?"
[This license] allows you to:
• freely download and use Apache software, in whole or in part, for personal, company internal, or
commercial purposes;
• use Apache software in packages or distributions that you create.
It forbids you to:

Maven: The Complete Reference 17 / 316
• redistribute any piece of Apache-originated software without proper attribution;
• use any marks owned by The Apache Software Foundation in any way that might state or imply that
the Foundation endorses your distribution;
• use any marks owned by The Apache Software Foundation in any way that might state or imply that
you created the Apache software in question.
It requires you to:
• include a copy of the license in any redistribution you may make that includes Apache software;
• provide clear attribution to The Apache Software Foundation for any distributions that include Apache
software.
It does not require you to:
• include the source of the Apache software itself, or of any modifications you may have made to it, in
any redistribution you may assemble that includes it;
• submit changes that you make to the software back to the Apache Software Foundation (though such
feedback is encouraged).

Maven: The Complete Reference 18 / 316
Chapter 3
The Project Object Model
3.1 Introduction
This chapter covers the central concept of Maven—the Project Object Model. The POM is where a
project’s identity and structure are declared, builds are configured, and projects are related to one another.
The presence of a pom.xml file defines a Maven project.
3.2 The POM
Maven projects, dependencies, builds, artifacts: all of these are objects to be modeled and described.
These objects are described by an XML file called a Project Object Model. The POM tells Maven what
sort of project it is dealing with and how to modify default behavior to generate output from source. In the
same way a Java web application has a web.xml that describes, configures, and customizes the application,
a Maven project is defined by the presence of a pom.xml. It is a descriptive declaration of a project for
Maven; it is the figurative “map” that Maven needs to understand what it is looking at when it builds your
project.
You could also think of the pom.xml as analogous to a Makefile or an Ant build.xml. When you are using
GNU make to build something like MySQL, you’ll usually have a file named Makefile that contains
explicit instructions for building a binary from source. When you are using Apache Ant, you likely have a

Maven: The Complete Reference 19 / 316
file named build.xml that contains explicit instructions for cleaning, compiling, packaging, and deploying
an application. make, Ant, and Maven are similar in that they rely on the presence of a commonly named
file such as Makefile,build.xml, or pom.xml, but that is where the similarities end. If you look at a Maven
pom.xml, the majority of the POM is going to deal with descriptions: Where is the source code? Where are
the resources? What is the packaging? If you look at an Ant build.xml file, you’ll see something entirely
different. You’ll see explicit instructions for tasks such as compiling a set of Java classes. The Maven
POM is declarative, and although you can certainly choose to include some procedural customizations
via the Maven Ant plugin, for the most part you will not need to get into the gritty procedural details of
your project’s build.
The POM is also not specific to building Java projects. While most of the examples in this book are
geared towards Java applications, there is nothing Java-specific in the definition of a Maven Project Object
Model. While Maven’s default plugins are targeted at building JAR artifacts from a set of source, tests, and
resources, there is nothing preventing you from defining a POM for a project that contains C# sources and
produces some proprietary Microsoft binary using Microsoft tools. Similarly, there is nothing stopping
you from defining a POM for a technical book. In fact, the source for this book and this book’s examples
is captured in a multi-module Maven project which uses one of the many Maven Docbook plugins to
apply the standard Docbook XSL to a series of chapter XML files. Others have created Maven plugins to
build Adobe Flex code into SWCs and SWFs, and yet others have used Maven to build projects written
in C.
We’ve established that the POM describes and declares, it is unlike Ant or Make in that it doesn’t provide
explicit instructions, and we’ve noted that POM concepts are not specific to Java. Diving into more
specifics, take a look at Figure 3.1 for a survey of the contents of a POM.

Maven: The Complete Reference 20 / 316
Figure 3.1: The Project Object Model
The POM contains four categories of description and configuration:
General project information
This includes a project’s name, the URL for a project, the sponsoring organization, and a list of
developers and contributors along with the license for a project.
Build settings
In this section, we customize the behavior of the default Maven build. We can change the location
of source and tests, we can add new plugins, we can attach plugin goals to the lifecycle, and we can
customize the site generation parameters.
Build environment
The build environment consists of profiles that can be activated for use in different environments.
For example, during development you may want to deploy to a development server, whereas in
production you want to deploy to a production server. The build environment customizes the build

Maven: The Complete Reference 21 / 316
settings for specific environments and is often supplemented by a custom settings.xml in ~/.m2.
This settings file is discussed in Chapter 5and in the section Section 15.2.
POM relationships
A project rarely stands alone; it depends on other projects, inherits POM settings from parent
projects, defines its own coordinates, and may include submodules.
3.2.1 The Super POM
Before we dive into some examples of POMs, let’s take a quick look at the Super POM. All Maven project
POMs extend the Super POM, which defines a set of defaults shared by all projects. This Super POM is
a part of the Maven installation. Depending on the Maven version it can be found in the maven-x.y.
z-uber.jar or maven-model-builder-xy.z.jar file in ${M2_HOME}/lib. If you look in this
JAR file, you will find a file named pom-4.0.0.xml under the org.apache.maven.model package. It
is also published on the Maven reference site that is available for each version of Maven separately and
e.g. for Maven 3.1.1 it can be found with the Maven Model Builder documentation. A Super POM for
Maven is shown in The Super POM.
Tip
An analogy to how the Super POM is the parent for all Maven POM files, would be how java.lang.
Object is the top of the class hierarchy for all Java classes.
The Super POM
<project>
<modelVersion>4.0.0</modelVersion>
<name>Maven Default Project</name>
<repositories>
<repository>
<id>central</id> v
1
<name>Maven Repository Switchboard</name>
<layout>default</layout>
<url>http://repo1.maven.org/maven2</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>

Maven: The Complete Reference 22 / 316
<pluginRepository>
<id>central</id> v
2
<name>Maven Plugin Repository</name>
<url>http://repo1.maven.org/maven2</url>
<layout>default</layout>
<snapshots>
<enabled>false</enabled>
</snapshots>
<releases>
<updatePolicy>never</updatePolicy>
</releases>
</pluginRepository>
</pluginRepositories>
<build> v
3
<directory>${project.basedir}/target</directory>
<outputDirectory>
${project.build.directory}/classes
</outputDirectory>
<finalName>${project.artifactId}-${project.version}</finalName ←-
>
<testOutputDirectory>
${project.build.directory}/test-classes
</testOutputDirectory>
<sourceDirectory>
${project.basedir}/src/main/java
</sourceDirectory>
<scriptSourceDirectory>src/main/scripts</scriptSourceDirectory ←-
>
<testSourceDirectory>
${project.basedir}/src/test/java
</testSourceDirectory>
<resources>
<resource>
<directory>${project.basedir}/src/main/resources</ ←-
directory>
</resource>
</resources>
<testResources>
<testResource>
<directory>${project.basedir}/src/test/resources</ ←-
directory>
</testResource>
</testResources>
<pluginManagement> v
4
<plugins>
<plugin>

Maven: The Complete Reference 23 / 316
<artifactId>maven-antrun-plugin</artifactId>
<version>1.3</version>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2-beta-2</version>
</plugin>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>2.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.0.2</version>
</plugin>
<plugin>
<artifactId>maven-dependency-plugin</ ←-
artifactId>
<version>2.0</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.4</version>
</plugin>
<plugin>
<artifactId>maven-ear-plugin</artifactId>
<version>2.3.1</version>
</plugin>
<plugin>
<artifactId>maven-ejb-plugin</artifactId>
<version>2.1</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.2</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>2.2</version>
</plugin>
<plugin>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.5</version>
</plugin>
<plugin>
<artifactId>maven-plugin-plugin</artifactId>
<version>2.4.3</version>
</plugin>
<plugin>

Maven: The Complete Reference 24 / 316
<artifactId>maven-rar-plugin</artifactId>
<version>2.2</version>
</plugin>
<plugin>
<artifactId>maven-release-plugin</artifactId>
<version>2.0-beta-8</version>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId ←-
>
<version>2.3</version>
</plugin>
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>2.0-beta-7</version>
</plugin>
<plugin>
<artifactId>maven-source-plugin</artifactId>
<version>2.0.4</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.4.3</version>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.1-alpha-2</version>
</plugin>
</plugins>
</pluginManagement>
<reporting>
<outputDirectory>target/site</outputDirectory>
</reporting>
</project>
The Super POM defines some standard configuration variables that are inherited by all projects. Those
values are captured in the annotated sections:
v
1The default Super POM defines a single remote Maven repository with an ID of central. This is
the Central Repository that all Maven clients are configured to read from by default. This setting
can be overridden by a custom settings.xml file. Note that the default Super POM has disabled
snapshot artifacts on the Central Repository. If you need to use a snapshot repository, you will
need to customize repository settings in your pom.xml or in your settings.xml. Settings and profiles
are covered in Chapter 5and in Section 15.2.

Maven: The Complete Reference 25 / 316
v
2The Central Repository also contains Maven plugins. The default plugin repository is the central
Maven repository. Snapshots are disabled, and the update policy is set to “never,” which means
that Maven will never automatically update a plugin if a new version is released.
v
3The build element sets the default values for directories in the Maven Standard Directory layout.
v
4Starting in Maven 2.0.9, default versions of core plugins have been provided in the Super POM.
This was done to provide some stability for users that are not specifying versions in their POMs.
In newer versions some of this has been migrated out of the file. However you can still see the
versions that will be used in your project using mvn help:effective-pom.
Figure 3.2: The Super POM is always the base Parent
3.2.2 The Simplest POM
All Maven POMs inherit defaults from the Super POM (introduced earlier in the section Section 3.2.1).
If you are just writing a simple project that produces a JAR from some source in src/main/java, want to
run your JUnit tests in src/test/java, and want to build a project site using mvn site, you don’t have to
customize anything. All you would need, in this case, is the simplest possible POM shown in The Simplest
POM. This POM defines a groupId,artifactId, and version: the three required coordinates for
every project.
The Simplest POM

Maven: The Complete Reference 26 / 316
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>org.sonatype.mavenbook.ch08</groupId>
<artifactId>simplest-project</artifactId>
<version>1</version>
</project>
Such a simple POM would be more than adequate for a simple project—e.g., a Java library that produces
a JAR file. It isn’t related to any other projects, it has no dependencies, and it lacks basic information
such as a name and a URL. If you were to create this file and then create the subdirectory src/main/java
with some source code, running mvn package would produce a JAR in target/simple-project-1.jar.
3.2.3 The Effective POM
$ mvn help:effective-pom
Executing the effective-pom goal should print out an XML document capturing the merge between
the Super POM and the POM from The Simplest POM.
3.2.4 Real POMs
Maven is something of a chameleon; you can pick and choose the features you want to take advantage of.
Some open source projects may value the ability to list developers and contributors, generate clean project
documentation, and manage releases automatically using the Maven Release plugin. On the other hand,
someone working in a corporate environment on a small team might not be interested in the distribution
management capabilities of Maven nor the ability to list developers. The remainder of this chapter is
going to discuss features of the POM in isolation. Instead of bombarding you with a 10-page listing of a
set of related POMs, we’re going to focus on creating a good reference for specific sections of the POM.
In this chapter, we discuss relationships between POMs, but we don’t illustrate such a project here.
3.3 POM Syntax
The POM is always in a file named pom.xml in the base directory of a Maven project. This XML document
can start with the XML declaration, or you can choose to omit it. All values in a POM are captured as

Maven: The Complete Reference 27 / 316
XML elements.
3.3.1 Project Versions
A project’s version number is used to group and order releases. Maven versions contain the following
parts: major version, minor version, incremental version, and qualifier. In a version, these parts corre-
spond to the following format:
<major version>.<minor version>.<incremental version>-<qualifier>
For example, the version "1.3.5" has a major version of 1, a minor version of 3, and an incremental version
of 5. The version "5" has a major version of 5 and no minor or incremental version. The qualifier exists
to capture milestone builds: alpha and beta releases, and the qualifier is separated from the major, minor,
and incremental versions by a hyphen. For example, the version "1.3-beta-01" has a major version of 1, a
minor version of 3, no incremental version and a qualifier of "beta-01".
Keeping your version numbers aligned with this standard will become very important when you want to
start using version ranges in your POMs. Version ranges, introduced in Section 3.4.3, allow you to specify
a dependency on a range of versions, and they are only supported because Maven has the ability to sort
versions based on the version release number format introduced in this section.
If your version release number matches the format <major>.<minor>.<incremental>-<quali
fier> then your versions will be compared properly; "1.2.3" will be evaluated as a more recent build than
"1.0.2", and the comparison will be made using the numeric values of the major, minor, and incremental
versions. If your version release number does not fit the standard introduced in this section, then your
versions will be compared as strings; "1.0.1b" will be compared to "1.2.0b" using a String comparison.
3.3.1.1 Version Build Numbers
One gotcha for release version numbers is the ordering of the qualifiers. Take the version release numbers
“1.2.3-alpha-2” and “1.2.3-alpha-10,” where the “alpha-2” build corresponds to the 2nd alpha build, and
the “alpha-10” build corresponds to the 10th alpha build. Even though “alpha-10” should be considered
more recent than “alpha-2,” Maven is going to sort “alpha-10” before “alpha-2” due to a known issue in
the way Maven handles version numbers.
Maven is supposed to treat the number after the qualifier as a build number. In other words, the qualifier
should be "alpha", and the build number should be 2. Even though Maven has been designed to separate

Maven: The Complete Reference 28 / 316
the build number from the qualifier, this parsing is currently broken. As a result, "alpha-2" and "alpha-
10" are compared using a String comparison, and "alpha-10" comes before "alpha-2" alphabetically. To
get around this limitation, you will need to left-pad your qualified build numbers. If you use "alpha-02"
and "alpha-10" this problem will go away, and it will continue to work once Maven properly parses the
version build number.
3.3.1.2 SNAPSHOT Versions
Maven versions can contain a string literal to signify that a project is currently under active development.
If a version contains the string “-SNAPSHOT,” then Maven will expand this token to a date and time
value converted to UTC (Coordinated Universal Time) when you install or release this component. For
example, if your project has a version of “1.0-SNAPSHOT” and you deploy this project’s artifacts to a
Maven repository, Maven would expand this version to “1.0-20080207-230803-1” if you were to deploy
a release at 11:08 PM on February 7th, 2008 UTC. In other words, when you deploy a snapshot, you are
not making a release of a software component; you are releasing a snapshot of a component at a specific
time.
Why would you use this? SNAPSHOT versions are used for projects under active development. If your
project depends on a software component that is under active development, you can depend on a SNAP-
SHOT release, and Maven will periodically attempt to download the latest snapshot from a repository
when you run a build. Similarly, if the next release of your system is going to have a version "1.4", your
project would have a version "1.4-SNAPSHOT" until it was formally released.
As a default setting, Maven will not check for SNAPSHOT releases on remote repositories. To depend
on SNAPSHOT releases, users must explicitly enable the ability to download snapshots using a reposi
tory or pluginRepository element in the POM.
When releasing a project, you should resolve all dependencies on SNAPSHOT versions to dependen-
cies on released versions. If a project depends on a SNAPSHOT, it is not stable as the dependencies may
change over time. Artifacts published to non-snapshot Maven repositories such as http://repo1.maven.org/-
maven2 cannot depend on SNAPSHOT versions, as Maven’s Super POM has snapshot’s disabled from
the Central repository. SNAPSHOT versions are for development only.
3.3.2 Property References
The syntax for using a property in Maven is to surround the property name with two curly braces and
precede it with a dollar symbol. For example, consider the following POM:

Maven: The Complete Reference 29 / 316
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>org.sonatype.mavenbook</groupId>
<artifactId>project-a</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<build>
<finalName>${project.groupId}-${project.artifactId}</finalName>
</build>
</project>
If you put this XML in a pom.xml and run mvn help:effective-pom, you will see that the output
contains the line:
...
<finalName>org.sonatype.mavenbook-project-a</finalName>
...
When Maven reads a POM, it replaces references to properties when it loads the POM XML. Maven
properties occur frequently in advanced Maven usage, and are similar to properties in other systems such
as Ant or Velocity. They are simply variables delimited by ${...}. Maven provides three implicit variables
which can be used to access environment variables, POM information, and Maven Settings:
env
The env variable exposes environment variables exposed by your operating system or shell. For
example, a reference to ${env.PATH} in a Maven POM would be replaced by the ${PATH} environ-
ment variable (or %PATH% in Windows).
project
The project variable exposes the POM. You can use a dot-notated (.) path to reference the value
of a POM element. For example, in this section we used the groupId and artifactId to set
the finalName element in the build configuration. The syntax for this property reference was:
${project.groupId}-${project.artifactId}.
settings
The settings variable exposes Maven settings information. You can use a dot-notated (.) path
to reference the value of an element in a settings.xml file. For example, ${settings.offline} would
reference the value of the offline element in ~/.m2/settings.xml.
Note
You may see older builds that use ${pom.xxx} or just ${xxx} to reference POM properties. These meth-
ods have been deprecated and only ${project.xxx} should be used.

Maven: The Complete Reference 30 / 316
In addition to the three implicit variables, you can reference system properties and any custom properties
set in the Maven POM or in a build profile:
Java System Properties
All properties accessible via getProperties() on java.lang.System are exposed as
POM properties. Some examples of system properties are: ${user.name},${user.home},${java.home},
and ${os.name}. A full list of system properties can be found in the Javadoc for the System class.
x
Arbitrary properties can be set with a properties element in a pom.xml or settings.xml, or
properties can be loaded from external files. If you set a property named fooBar in your pom.xml,
that same property is referenced with ${fooBar}. Custom properties come in handy when you are
building a system that filters resources and targets different deployment platforms. Here is the
syntax for setting ${foo}=bar in a POM:
<properties>
<foo>bar</foo>
</properties>
For a more comprehensive list of available properties, see Chapter 9.
3.4 Project Dependencies
Maven can manage both internal and external dependencies. An external dependency for a Java project
might be a library such as Plexus, the Spring Framework, or Log4J. An internal dependency is illustrated
by a web application project depending on another project that contains service classes, model objects, or
persistence logic. Project Dependencies shows some examples of project dependencies.
Project Dependencies
<project>
...
<dependencies>
<dependency>
<groupId>org.codehaus.xfire</groupId>
<artifactId>xfire-java5</artifactId>
<version>1.2.5</version>
</dependency>
<dependency>
<groupId>junit</groupId>

Maven: The Complete Reference 31 / 316
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.4</version>
<scope>provided</scope>
</dependency>
</dependencies>
...
</project>
The first dependency is a compile dependency on the XFire SOAP library from Codehaus. You would
use this type of dependency if your project depended on this library for compilation, testing, and during
execution. The second dependency is a test-scoped dependency on JUnit. You would use a test-
scoped dependency when you need to reference this library only during testing. The last dependency in
Project Dependencies is a dependency on the Servlet 2.4 API. The last dependency is scoped as a provided
dependency. You would use a provided scope when the application you are developing needs a library for
compilation and testing, but this library is supplied by a container at runtime.
3.4.1 Dependency Scope
Project Dependencies briefly introduced three of the five dependency scopes: compile,test, and pro
vided. Scope controls which dependencies are available in which classpath, and which dependencies
are included with an application. Let’s explore each scope in detail:
compile
compile is the default scope; all dependencies are compile-scoped if a scope is not supplied.
compile dependencies are available in all classpaths, and they are packaged.
provided
provided dependencies are used when you expect the JDK or a container to provide them. For
example, if you were developing a web application, you would need the Servlet API available on
the compile classpath to compile a servlet, but you wouldn’t want to include the Servlet API in the
packaged WAR; the Servlet API JAR is supplied by your application server or servlet container.
provided dependencies are available on the compilation classpath (not runtime). They are not
transitive, nor are they packaged.
runtime
runtime dependencies are required to execute and test the system, but they are not required for

Maven: The Complete Reference 32 / 316
compilation. For example, you may need a JDBC API JAR at compile time and the JDBC driver
implementation only at runtime.
test
test-scoped dependencies are not required during the normal operation of an application, and
they are available only during test compilation and execution phases.
system
The system scope is similar to provided except that you have to provide an explicit path to the
JAR on the local file system. This is intended to allow compilation against native objects that may
be part of the system libraries. The artifact is assumed to always be available and is not looked up
in a repository. If you declare the scope to be system, you must also provide the systemPath
element. Note that this scope is not recommended (you should always try to reference dependencies
in a public or custom Maven repository).
3.4.2 Optional Dependencies
Assume that you are working on a library that provides caching behavior. Instead of writing a caching
system from scratch, you want to use some of the existing libraries that provide caching on the file
system and distributed caches. Also assume that you want to give the end user an option to cache on
the file system or to use an in-memory distributed cache. To cache on the file system, you’ll want to
use a freely available library called EHCache (http://ehcache.sourceforge.net/), and to cache in a dis-
tributed in-memory cache, you want to use another freely available caching library named SwarmCache (
http://swarmcache.sourceforge.net/ ). You’ll code an interface and create a library that can be configured
to use either EHCache or SwarmCache, but you want to avoid adding a dependency on both caching
libraries to any project that depends on your library.
In other words, you need both libraries to compile this library project, but you don’t want both libraries
to show up as transitive runtime dependencies for the project that uses your library. You can accomplish
this by using optional dependencies as shown in Declaring Optional Dependencies.
Declaring Optional Dependencies
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>org.sonatype.mavenbook</groupId>
<artifactId>my-project</artifactId>
<version>1.0.0</version>
<dependencies>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>1.4.1</version>

Maven: The Complete Reference 33 / 316
<optional>true</optional>
</dependency>
<dependency>
<groupId>swarmcache</groupId>
<artifactId>swarmcache</artifactId>
<version>1.0RC2</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.13</version>
</dependency>
</dependencies>
</project>
Since you’ve declared these dependencies as optional in my-project, if you’ve defined a project that
depends on my-project which needs those dependencies, you’ll have to include them explicitly in the
project that depends on my-project. For example, if you were writing an application which depended
on my-project and wanted to use the EHCache implementation, you would need to add the following
dependency element to your project.
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>org.sonatype.mavenbook</groupId>
<artifactId>my-application</artifactId>
<version>1.0.0</version>
<dependencies>
<dependency>
<groupId>org.sonatype.mavenbook</groupId>
<artifactId>my-project</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>1.4.1</version>
</dependency>
</dependencies>
</project>
In an ideal world, you wouldn’t have to use optional dependencies. Instead of having one large project
with a series of optional dependencies, you would separate the EHCache-specific code to a my-proj
ect-ehcache submodule and the SwarmCache-specific code to a my-project-swarmcache sub-
module. This way, instead of requiring projects that reference my-project to specifically add a de-
pendency, projects can just reference a particular implementation project and benefit from the transitive

Maven: The Complete Reference 34 / 316
dependency.
3.4.3 Dependency Version Ranges
Instead of a specific version for each dependency, you can alternatively specify a range of versions that
would satisfy a given dependency. For example, you can specify that your project depends on version 3.8
or greater of JUnit, or anything between versions 4.5 and 4.10 of JUnit. You do this by surrounding one
or more version numbers with the following characters:
(, )
Exclusive quantifiers
[, ]
Inclusive quantifiers
For example, if you wished to access any JUnit version greater than or equal to 3.8 but less than 4.0,
your dependency would be as shown in Specifying a Dependency Range: JUnit 3.8 - JUnit 4.0.
Specifying a Dependency Range: JUnit 3.8 - JUnit 4.0
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>[3.8,4.0)</version>
<scope>test</scope>
</dependency>
If you want to depend on any version of JUnit no higher than 3.8.1, you would specify only an upper
inclusive boundary, as shown in Specifying a Dependency Range: JUnit ⇐3.8.1.
Specifying a Dependency Range: JUnit ⇐3.8.1
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>[,3.8.1]</version>
<scope>test</scope>
</dependency>

Maven: The Complete Reference 35 / 316
A version before or after the comma is not required, and means +/- infinity. For example, "[4.0,)" means
any version greater than or equal to 4.0. "(,2.0)" is any version less than 2.0. "[1.2]" means only version
1.2, and nothing else.
Note
When declaring a "normal" version such as 3.8.2 for Junit, internally this is represented as "allow any-
thing, but prefer 3.8.2." This means that when a conflict is detected, Maven is allowed to use the conflict
algorithms to choose the best version. If you specify [3.8.2], it means that only 3.8.2 will be used and
nothing else. If somewhere else there is a dependency that specifies [3.8.1], you would get a build
failure telling you of the conflict. We point this out to make you aware of the option, but use it sparingly
and only when really needed. The preferred way to resolve this is via dependencyManagement.
3.4.4 Transitive Dependencies
project-a depends on project-b, which in turn depends on project-c, then project-c is
considered a transitive dependency of project-a. If project-c depended on project-d, then
project-d would also be considered a transitive dependency of project-a. Part of Maven’s appeal
is that it can manage transitive dependencies and shield the developer from having to keep track of all
of the dependencies required to compile and run an application. You can just depend on something like
the Spring Framework and not have to worry about tracking down every last dependency of the Spring
Framework.
Maven accomplishes this by building a graph of dependencies and dealing with any conflicts and overlaps
that might occur. For example, if Maven sees that two projects depend on the same groupId and artif
actId, it will sort out which dependency to use automatically, always favoring the more recent version of
a dependency. Although this sounds convenient, there are some edge cases where transitive dependencies
can cause some configuration issues. For these scenarios, you can use a dependency exclusion.
3.4.4.1 Transitive Dependencies and Scope
Each of the scopes outlined earlier in the section Section 3.4.1 affects not just the scope of the dependency
in the declaring project, but also how it acts as a transitive dependency. The easiest way to convey this
information is through a table, as in Table 3.1. Scopes in the top row represent the scope of a transitive
dependency. Scopes in the leftmost column represent the scope of a direct dependency. The intersection
of the row and column is the scope that is assigned to a transitive dependency. A blank cell in this table
means that the transitive dependency will be omitted.

Maven: The Complete Reference 36 / 316
Table 3.1: How Scope Affects Transitive Dependencies
Direct Scope vs. Transitive Scope
compile provided runtime test
compile compile - runtime -
provided provided - provided -
runtime runtime - runtime -
test test - test -
To illustrate the relationship of transitive dependency scope to direct dependency scope, consider the
following example. If project-a contains a test scoped dependency on project-b which contains a
compile scoped dependency on project-c.project-c would be a test-scoped transitive dependency
of project-a.
You can think of this as a transitive boundary which acts as a filter on dependency scope. Transitive
dependencies which are provided and test scope usually do not affect a project. Transitive dependen-
cies which are compile and runtime scoped usually affect a project regardless of the scope of a direct
dependency. Transitive dependencies which are compile scoped will have the same scope of the direct
dependency . Transitive dependencies which are runtime scoped will generally have the same scope of
the direct dependency except when the direct dependency has a scope of compile. When a transitive de-
pendency is runtime scoped and the direct dependency is compile scoped, the transitive dependency will
have an effective scope of runtime.
3.4.5 Conflict Resolution
There will be times when you need to exclude a transitive dependency, such as when you are depending
on a project that depends on another project, but you would like to either exclude the dependency alto-
gether or replace the transitive dependency with another dependency that provides the same functionality.
Excluding a Transitive Dependency shows an example of a dependency element that adds a dependency
on project-a, but excludes the transitive dependency project-b.
Excluding a Transitive Dependency
<dependency>
<groupId>org.sonatype.mavenbook</groupId>
<artifactId>project-a</artifactId>
<version>1.0</version>

Maven: The Complete Reference 37 / 316
<exclusions>
<exclusion>
<groupId>org.sonatype.mavenbook</groupId>
<artifactId>project-b</artifactId>
</exclusion>
</exclusions>
</dependency>
Often, you will want to replace a transitive dependency with another implementation. For example, if
you are depending on a library that depends on the Sun JTA API, you may want to replace the declared
transitive dependency. Hibernate is one example. Hibernate depends on the Sun JTA API JAR, which is
not available in the central Maven repository because it cannot be freely redistributed. Fortunately, the
Apache Geronimo project has created an independent implementation of this library that can be freely
redistributed. To replace a transitive dependency with another dependency, you would exclude the transi-
tive dependency and declare a dependency on the project you wanted instead. Excluding and Replacing a
Transitive Dependency shows an example of a such replacement.
Excluding and Replacing a Transitive Dependency
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate</artifactId>
<version>3.2.5.ga</version>
<exclusions>
<exclusion>
<groupId>javax.transaction</groupId>
<artifactId>jta</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-jta_1.1_spec</artifactId>
<version>1.1</version>
</dependency>
</dependencies>
In Excluding and Replacing a Transitive Dependency, there is nothing marking the dependency on geronimo-
jta_1.1_spec as a replacement, it just happens to be a library which provides the same API as the original
JTA dependency. Here are some other reasons you might want to exclude or replace transitive dependen-
cies:
1. The groupId or artifactId of the artifact has changed, where the current project requires an

Maven: The Complete Reference 38 / 316
alternately named version from a dependency’s version - resulting in 2 copies of the same project in
the classpath. Normally Maven would capture this conflict and use a single version of the project,
but when groupId or artifactId are different, Maven will consider this to be two different
libraries.
2. An artifact is not used in your project and the transitive dependency has not been marked as an op-
tional dependency. In this case, you might want to exclude a dependency because it isn’t something
your system needs and you are trying to cut down on the number of libraries distributed with an
application.
3. An artifact which is provided by your runtime container thus should not be included with your build.
An example of this is if a dependency depends on something like the Servlet API and you want to
make sure that the dependency is not included in a web application’s WEB-INF/lib directory.
4. To exclude a dependency which might be an API with multiple implementations. This is the sit-
uation illustrated by Excluding and Replacing a Transitive Dependency; there is a Sun API which
requires click-wrap licensing and a time-consuming manual install into a custom repository (Sun’s
JTA JAR) versus a freely distributed version of the same API available in the central Maven repos-
itory (Geronimo’s JTA implementation). ==== Dependency Management
Once you’ve adopted Maven at your super complex enterprise and you have two hundred and twenty
inter-related Maven projects, you are going to start wondering if there is a better way to get a handle on
dependency versions. If every single project that uses a dependency like the MySQL Java connector needs
to independently list the version number of the dependency, you are going to run into problems when you
need to upgrade to a new version. Because the version numbers are distributed throughout your project
tree, you are going to have to manually edit each of the pom.xml files that reference a dependency to make
sure that you are changing the version number everywhere. Even with find,xargs, and awk, you are
still running the risk of missing a single POM.
Luckily, Maven provides a way for you to consolidate dependency version numbers in the dependency
Management element. You’ll usually see the dependencyManagement element in a top-level parent
POM for an organization or project. Using the dependencyManagement element in a pom.xml allows
you to reference a dependency in a child project without having to explicitly list the version. Maven will
walk up the parent-child hierarchy until it finds a project with a dependencyManagement element, it
will then use the version specified in this dependencyManagement element.
For example, if you have a large set of projects which make use of the MySQL Java connector ver-
sion 5.1.2, you could define the following dependencyManagement element in your multi-module
project’s top-level POM.
Defining Dependency Versions in a Top-level POM
<project>
<modelVersion>4.0.0</modelVersion>

Maven: The Complete Reference 39 / 316
<groupId>org.sonatype.mavenbook</groupId>
<artifactId>a-parent</artifactId>
<version>1.0.0</version>
...
<dependencyManagement>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.2</version>
<scope>runtime</scope>
</dependency>
...
<dependencies>
</dependencyManagement>
Then, in a child project, you can add a dependency to the MySQL Java Connector using the following
dependency XML:
<project>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.sonatype.mavenbook</groupId>
<artifactId>a-parent</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>project-a</artifactId>
...
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
</project>
You should notice that the child project did not have to explicitly list the version of the mysql-connec
tor-java dependency. Because this dependency was defined in the top-level POM’s dependencyMan-
agement element, the version number is going to propagate to the child project’s dependency on mysql-
connector-java. Note that if this child project did define a version, it would override the version
listed in the top-level POM’s dependencyManagement section. That is, the dependencyManage
ment version is only used when the child does not declare a version directly.
Dependency management in a top-level POM is different from just defining a dependency on a widely
shared parent POM. For starters, all dependencies are inherited. If mysql-connector-java were

Maven: The Complete Reference 40 / 316
listed as a dependency of the top-level parent project, every single project in the hierarchy would have
a reference to this dependency. Instead of adding in unnecessary dependencies, using dependencyM
anagement allows you to consolidate and centralize the management of dependency versions without
adding dependencies which are inherited by all children. In other words, the dependencyManagem
ent element is equivalent to an environment variable which allows you to declare a dependency anywhere
below a project without specifying a version number.
3.5 Project Relationships
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-
adepends 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.
3.5.1 More on Coordinates
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,artifac
tId, and version depends on another project with a groupId,artifactId, and version. To
review, a Maven Coordinate is made up of three components:
groupId
AgroupId groups a set of related artifacts. Group identifiers generally resemble a Java package
name. For example, the groupId org.apache.maven is the base groupId for all artifacts pro-
duced by the Apache Maven project. Group identifiers are translated into paths in the Maven Repos-
itory; for example, the org.apache.maven groupId can be found in /maven2/org/apache/maven on
repo1.maven.org.
artifactId
The artifactId is the project’s main identifier. When you generate an artifact, this artifact is

Maven: The Complete Reference 41 / 316
going to be named with the artifactId. When you refer to a project, you are going to refer
to it using the artifactId. The artifactId,groupId combination must be unique. In
other words, you can’t have two separate projects with the same artifactId and groupId;
artifactId s are unique within a particular groupId.
Note
While ’.’s are commonly used in groupId s, you should try to avoid using them in artifactId s.
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 ver-
sion numbers always end in SNAPSHOT; for example, "1.0-SNAPSHOT", "1.1.1-SNAPSHOT",
and "1-SNAPSHOT". Section 3.3.1.1 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.

Maven: The Complete Reference 42 / 316
3.5.2 Project Inheritance
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. Project Inheritance shows the
parent element of project-a which inherits the POM defined by the a-parent project.
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 merg-
ing 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.

Maven: The Complete Reference 43 / 316
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 groupId or artifactId must be overridden.)
• dependencies
• developers and contributors
• plugin lists
• reports lists

Maven: The Complete Reference 44 / 316
• 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>
3.6 POM Best Practices
Maven can be used to manage everything from simple, single-project systems to builds that involve hun-
dreds of inter-related submodules. Part of the learning process with Maven isn’t just figuring out the
syntax for configuring Maven, it is learning the "Maven Way"—the current set of best practices for orga-
nizing and building projects using Maven. This section attempts to distill some of this knowledge to help
you adopt best practices from the start without having to wade through years of discussions on the Maven
mailing lists.

Maven: The Complete Reference 45 / 316
3.6.1 Grouping Dependencies
If you have a set of dependencies which are logically grouped together. You can create a project with
pom packaging that groups dependencies together. For example, let’s assume that your application uses
Hibernate, a popular Object-Relational mapping framework. Every project which uses Hibernate might
also have a dependency on the Spring Framework and a MySQL JDBC driver. Instead of having to include
these dependencies in every project that uses Hibernate, Spring, and MySQL you could create a special
POM that does nothing more than declare a set of common dependencies. You could create a project
called persistence-deps (short for Persistence Dependencies), and have every project that needs to
do persistence depend on this convenience project:
Consolidating Dependencies in a Single POM Project
<project>
<groupId>org.sonatype.mavenbook</groupId>
<artifactId>persistence-deps</artifactId>
<version>1.0</version>
<packaging>pom</packaging>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate</artifactId>
<version>${hibernateVersion}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-annotations</artifactId>
<version>${hibernateAnnotationsVersion}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-hibernate3</artifactId>
<version>${springVersion}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysqlVersion}</version>
</dependency>
</dependencies>
<properties>
<mysqlVersion>(5.1,)</mysqlVersion>
<springVersion>(2.0.6,)</springVersion>
<hibernateVersion>3.2.5.ga</hibernateVersion>
<hibernateAnnotationsVersion>3.3.0.ga</hibernateAnnotationsVersion ←-
>
</properties>

Maven: The Complete Reference 46 / 316
</project>
If you create this project in a directory named persistence-deps, all you need to do is create this
pom.xml and run mvn install. Since the packaging type is pom, this POM is installed in your local
repository. You can now add this project as a dependency and all of its dependencies will be added as
transitive dependencies to your project. When you declare a dependency on this persistence-deps project,
don’t forget to specify the dependency type as pom.
Declaring a Dependency on a POM
<project>
<description>This is a project requiring JDBC</description>
...
<dependencies>
...
<dependency>
<groupId>org.sonatype.mavenbook</groupId>
<artifactId>persistence-deps</artifactId>
<version>1.0</version>
<type>pom</type>
</dependency>
</dependencies>
</project>
If you later decide to switch to a different JDBC driver (for example, JTDS), just replace the dependencies
in the persistence-deps project to use net.sourceforge.jtds:jtds instead of mysql:
mysql-java-connector and update the version number. All projects depending on persiste
nce-deps will use JTDS if they decide to update to the newer version. Consolidating related depen-
dencies is a good way to cut down on the length of pom.xml files that start having to depend on a large
number of dependencies. If you need to share a large number of dependencies between projects, you
could also just establish parent-child relationships between projects and refactor all common dependen-
cies to the parent project, but the disadvantage of the parent-child approach is that a project can have only
one parent. Sometimes it makes more sense to group similar dependencies together and reference a pom
dependency. This way, your project can reference as many of these consolidated dependency POMs as it
needs.
Note
Maven uses the depth of a dependency in the tree when resolving conflicts using a nearest-
wins approach. Using the dependency grouping technique above pushes those dependencies one
level down in the tree. Keep this in mind when choosing between grouping in a pom or using
dependencyManagement in a parent POM

Maven: The Complete Reference 47 / 316
3.6.2 Multi-module vs. Inheritance
There is a difference between inheriting from a parent project and being managed by a multimodule
project. A parent project is one that passes its values to its children. A multimodule project simply
manages a group of other subprojects or modules. The multimodule relationship is defined from the
topmost level downwards. When setting up a multimodule project, you are simply telling a project that its
build should include the specified modules. Multimodule builds are to be used to group modules together
in a single build. The parent-child relationship is defined from the leaf node upwards. The parent-child
relationship deals more with the definition of a particular project. When you associate a child with its
parent, you are telling Maven that a project’s POM is derived from another.
To illustrate the decision process that goes into choosing a design that uses inheritance vs. multi-module
or both approaches consider the following two examples: the Maven project used to generate this book
and a hypothetical project that contains a number of logically grouped modules.
3.6.2.1 Simple Project
First, let’s take a look at the maven-book project. The inheritance and multi-module relationships are
shown in Figure 3.4.

Maven: The Complete Reference 48 / 316
Figure 3.4: maven-book Multi-module vs. Inheritance
When we build this Maven book you are reading, we run mvn package in a multi-module project
named maven-book. This multi-module project includes two submodules: book-examples and
book-chapters. Neither of these projects share the same parent, they are related only in that they
are modules in the maven-book project. book-examples builds the ZIP and TGZ archives you
downloaded to get this book’s example. When we run the book-examples build from book-examples/
directory with mvn package, it has no knowledge that it is a part of the larger maven-book project.
book-examples doesn’t really care about maven-book, all it knows in life is that its parent is the
top-most sonatype POM and that it creates an archive of examples. In this case, the maven-book
project exists only as a convenience and as an aggregator of modules.
Each of the three projects: maven-book,book-examples, and book-chapters all list a shared
"corporate" parent — sonatype. This is a common practice in organizations which have adopted
Maven, instead of having every project extend the Super POM by default, some organizations define
a top-level corporate POM that serves as the default parent when a project doesn’t have any good reason

Maven: The Complete Reference 49 / 316
to depend on another. In this book example, there is no compelling reason to have book-examples
and book-chapters share the same parent POM, they are entirely different projects which have a dif-
ferent set of dependencies, a different build configuration, and use drastically different plugins to create
the content you are now reading. The sonatype POM gives the organization a chance to customize the
default behavior of Maven and supply some organization-specific information to configure deployment
settings and build profiles.
3.6.2.2 Multi-module Enterprise Project
Let’s take a look at an example that provides a more accurate picture of a real-world project where inher-
itance and multi-module relationships exist side by side. Figure 3.5 shows a collection of projects that
resemble a typical set of projects in an enterprise application. There is a top-level POM for the corpora-
tion with an artifactId of sonatype. There is a multi-module project named big-system which
references sub-modules server-side and client-side.

Maven: The Complete Reference 50 / 316
Figure 3.5: Enterprise Multi-module vs. Inheritance
What’s going on here? Let’s try to deconstruct this confusing set of arrows. First, let’s take a look at
big-system. The big-system might be the project that you would run mvn package on to build
and test the entire system. big-system references submodules client-side and server-side.
Each of these projects effectively rolls up all of the code that runs on either the server or on the client.
Let’s focus on the server-side project. Under the server-side project we have a project called
server-lib and a multi-module project named web-apps. Under web-apps we have two Java web
applications: client-web and admin-web.
Let’s start with the parent/child relationships from client-web and admin-web to web-apps. Since
both of the web applications are implemented in the same web application framework (let’s say Wicket),
both projects would share the same set of core dependencies. The dependencies on the Servlet API, the
JSP API, and Wicket would all be captured in the web-apps project. Both client-web and admin-

Maven: The Complete Reference 51 / 316
web also need to depend on server-lib, this dependency would be defined as a dependency between
web-apps and server-lib. Because client-web and admin-web share so much configura-
tion by inheriting from web-apps, both client-web and admin-web will have very small POMs
containing little more than identifiers, a parent declaration, and a final build name.
Next we focus on the parent/child relationship from web-apps and server-lib to server-side.
In this case, let’s just assume that there is a separate working group of developers which work on the
server-side code and another group of developers that work on the client-side code. The list of devel-
opers would be configured in the server-side POM and inherited by all of the child projects under-
neath it: web-apps,server-lib,client-web, and admin-web. We could also imagine that
the server-side project might have different build and deployment settings which are unique to the
development for the server side. The server-side project might define a build profile that only makes
sense for all of the server-side projects. This build profile might contain the database host and cre-
dentials, or the server-side project’s POM might configure a specific version of the Maven Jetty
plugin which should be universal across all projects that inherit the server-side POM.
In this example, the main reason to use parent/child relationships is shared dependencies and common
configuration for a group of projects which are logically related. All of the projects below big-system
are related to one another as submodules, but not all submodules are configured to point back to parent
project that included it as a submodule. Everything is a submodule for reasons of convenience, to build
the entire system just go to the big-system project directory and run mvn package. Look more
closely at the figure and you’ll see that there is no parent/child relationship between server-side and
big-system. Why is this? POM inheritance is very powerful, but it can be overused. When it makes
sense to share dependencies and build configuration, a parent/child relationship should be used. When
it doesn’t make sense is when there are distinct differences between two projects. Take, for example,
the server-side and client-side projects. It is possible to create a system where client-
side and server-side inherited a common POM from big-system, but as soon as a significant
divergence between the two child projects develops, you then have to figure out creative ways to factor
out common build configuration to big-system without affecting all of the children. Even though
client-side and server-side might both depend on Log4J, they also might have distinct plugin
configurations.
There’s a certain point defined more by style and experience where you decide that minimal duplication
of configuration is a small price to pay for allowing projects like client-side and server-side to
remain completely independent. Designing a huge set of thirty plus projects which all inherit five levels
of POM configuration isn’t always the best idea. In such a setup, you might not have to duplicate your
Log4J dependency more than once, but you’ll also end up having to wade through five levels of POM
just figure out how Maven calculated your effective POM. All of this complexity to avoid duplicating
five lines of dependency declaration. In Maven, there is a "Maven Way", but there are also many ways
to accomplish the same thing. It all boils down to preference and style. For the most part, you won’t go
wrong if all of your submodules turn out to define back-references to the same project as a parent, but
your use of Maven may evolve over time.

Maven: The Complete Reference 52 / 316
Chapter 4
The Build Lifecycle
4.1 Introduction
Maven models projects as nouns which are described by a POM. The POM captures the identity of a
project: What does a project contain? What type of packaging a project needs? Does the project have
a parent? What are the dependencies? We’ve explored the idea of describing a project in the previous
chapters, but we haven’t introduced the mechanism that allows Maven to act upon these objects. In Maven
the "verbs" are goals packaged in Maven plugins which are tied to a phases in a build lifecycle. A Maven
lifecycle consists of a sequence of named phases: prepare-resources, compile, package, and install among
other. There is phase that captures compilation and a phase that captures packaging. There are pre- and
post- phases which can be used to register goals which must run prior to compilation, or tasks which must
be run after a particular phase. When you tell Maven to build a project, you are telling Maven to step
through a defined sequence of phases and execute any goals which may have been registered with each
phase.
A build lifecycle is an organized sequence of phases that exist to give order to a set of goals. Those goals
are chosen and bound by the packaging type of the project being acted upon. There are three standard
lifecycles in Maven: clean, default (sometimes called build) and site. In this chapter, you are going to
learn how Maven ties goals to lifecycle phases and how the lifecycle can be customized. You will also
learn about the default lifecycle phases.

Maven: The Complete Reference 53 / 316
4.1.1 Clean Lifecycle (clean)
The first lifecycle you’ll be interested in is the simplest lifecycle in Maven. Running mvn clean invokes
the clean lifecycle which consists of three lifecycle phases:
•pre-clean
•clean
•post-clean
The interesting phase in the clean lifecycle is the clean phase. The Clean plugin’s clean goal (clean:
clean) is bound to the clean phase in the clean lifecycle. The clean:clean goal deletes the
output of a build by deleting the build directory. If you haven’t customized the location of the build
directory it will be the ${basedir}/target directory as defined by the Super POM. When you execute the
clean:clean goal you do not do so by executing the goal directly with mvn clean:clean, you
do so by executing the clean phase of the clean lifecycle. Executing the clean phase gives Maven an
opportunity to execute any other goals which may be bound to the pre-clean phase.
For example, suppose you wanted to trigger an antrun:run goal task to echo a notification on pre-
clean, or to make an archive of a project’s build directory before it is deleted. Simply running the
clean:clean goal will not execute the lifecycle at all, but specifying the clean phase will use the
clean lifecycle and advance through the three lifecycle phases until it reaches the clean phase. Trig-
gering a Goal on pre-clean shows an example of build configuration which binds the antrun:run goal
to the pre-clean phase to echo an alert that the project artifact is about to be deleted. In this example,
the antrun:run goal is being used to execute some arbitrary Ant commands to check for an existing
project artifact. If the project’s artifact is about to be deleted it will print this to the screen
Triggering a Goal on pre-clean
<project>
...
<build>
<plugins>... <plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>file-exists</id>
<phase>pre-clean</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>

Maven: The Complete Reference 54 / 316
<tasks>
<!-- adds the ant-contrib tasks (if/then/ ←-
else used below) -->
<taskdef resource="net/sf/antcontrib/ ←-
antcontrib.properties" />
<available
file="${project.build.directory}/${ ←-
project.build.finalName}.${project ←-
.packaging}"
property="file.exists" value="true" ←-
/>
<if>
<not>
<isset property="file.exists" />
</not>
<then>
<echo>No
${project.build.finalName}.${ ←-
project.packaging} to
delete</echo>
</then>
<else>
<echo>Deleting
${project.build.finalName}.${ ←-
project.packaging}</echo>
</else>
</if>
</tasks>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>ant-contrib</groupId>
<artifactId>ant-contrib</artifactId>
<version>1.0b2</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</project>
Running mvn clean on a project with this build configuration will produce output similar to the fol-
lowing:
[INFO] Scanning for projects...

Maven: The Complete Reference 55 / 316
[INFO] ←-
----------------------------------------------------------------------
[INFO] Building Your Project
[INFO]task-segment: [clean]
[INFO] ←-
----------------------------------------------------------------------
[INFO] [antrun:run {execution: file-exists}]
[INFO] Executing tasks
[echo] Deleting your-project-1.0-SNAPSHOT.jar
[INFO] Executed tasks
[INFO] [clean:clean]
[INFO] Deleting directory ~/corp/your-project/target
[INFO] Deleting directory ~/corp/your-project/target/classes
[INFO] Deleting directory ~/corp/your-project/target/test-classes
[INFO] ←-
------------------------------------------------------------------------ ←-
[INFO] BUILD SUCCESSFUL
[INFO] ←-
------------------------------------------------------------------------ ←-
[INFO] Total time: 1 second
[INFO] Finished at: Wed Nov 08 11:46:26 CST 2006
[INFO] Final Memory: 2M/5M
[INFO] ←-
------------------------------------------------------------------------ ←-
In addition to configuring Maven to run a goal during the pre-clean phase, you can also customize
the Clean plugin to delete files in addition to the build output directory. You can configure the plugin to
remove specific files in a fileSet. The example below configures clean to remove all .class files in a
directory named target-other/ using standard Ant file wildcards: *and \**.
Customizing Behavior of the Clean Plugin
<project>
<modelVersion>4.0.0</modelVersion>
...
<build>
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<configuration>
<filesets>
<fileset>
<directory>target-other</directory>
<includes>

Maven: The Complete Reference 56 / 316
<include>*.class</include>
</includes>
</fileset>
</filesets>
</configuration>
</plugin>
</plugins>
</build>
</project>
4.1.2 Default Lifecycle (default)
Most Maven users will be familiar with the default lifecycle. It is a general model of a build process for
a software application. The first phase is validate and the last phase is deploy. The phases in the
default Maven lifecycle are shown in Table 4.1.
Table 4.1: Maven Lifecycle Phases
Lifecycle Phase Description
validate Validate the project is correct and all necessary
information is available to complete a build
generate-sources Generate any source code for inclusion in
compilation
process-sources Process the source code, for example to filter
any values
generate-resources Generate resources for inclusion in the package
process-resources Copy and process the resources into the
destination directory, ready for packaging
compile Compile the source code of the project
process-classes Post-process the generated files from
compilation, for example to do bytecode
enhancement on Java classes
generate-test-sources Generate any test source code for inclusion in
compilation
process-test-sources Process the test source code, for example to
filter any values
generate-test-resources Create resources for testing
process-test-resources Copy and process the resources into the test
destination directory
test-compile Compile the test source code into the test
destination directory

Maven: The Complete Reference 57 / 316
Table 4.1: (continued)
Lifecycle Phase Description
test Run tests using a suitable unit testing
framework. These tests should not require the
code be packaged or deployed
prepare-package Perform any operations necessary to prepare a
package before the actual packaging. This often
results in an unpacked, processed version of the
package (coming in Maven 2.1+)
package Take the compiled code and package it in its
distributable format, such as a JAR, WAR, or
EAR
pre-integration-test Perform actions required before integration
tests are executed. This may involve things
such as setting up the required environment
integration-test Process and deploy the package if necessary
into an environment where integration tests can
be run
post-integration-test Perform actions required after integration tests
have been executed. This may include cleaning
up the environment
verify Run any checks to verify the package is valid
and meets quality criteria
install Install the package into the local repository, for
use as a dependency in other projects locally
deploy Copies the final package to the remote
repository for sharing with other developers
and projects (usually only relevant during a
formal release)
4.1.3 Site Lifecycle (site)
Maven does more than build software artifacts from project, it can also generate project documentation
and reports about the project, or a collection of projects. Project documentation and site generation have
a dedicated lifecycle which contains four phases:
1. pre-site

Maven: The Complete Reference 58 / 316
2. site
3. post-site
4. site-deploy
The default goals bound to the site lifecycle is:
1. site - site:site
2. site-deploy -site:deploy
The packaging type does not usually alter this lifecycle since packaging types are concerned primarily
with artifact creation, not with the type of site generated. The Site plugin kicks off the execution of Doxia
document generation and other report generation plugins. You can generate a site from a Maven project
by running the following command:
$ mvn site
For more information about Maven Site generation, see Chapter 10.
4.2 Package-specific Lifecycles
The specific goals bound to each phase default to a set of goals specific to a project’s packaging. A project
with packaging jar has a different set of default goals from a project with a packaging of war. The
packaging element affects the steps required to build a project. For an example of how the packaging
affects the build, consider two projects: one with pom packaging and the other with jar packaging.
The project with pom packaging will run the site:attach-descriptor goal during the package
phase, and the project with jar packaging will run the jar:jar goal instead.
The following sections describe the lifecycle for all built-in packaging types in Maven. Use these sections
to find out what default goals are mapped to default lifecycle phases.

Maven: The Complete Reference 59 / 316
4.2.1 JAR
JAR is the default packaging type, the most common, and thus the most commonly encountered lifecycle
configuration. The default goals for the JAR lifecycle are shown in Table 4.2.
Table 4.2: Default Goals for JAR Packaging
Lifecycle Phase Goal
process-resources resources:resources
compile compiler:compile
process-test-resources resources:testResources
test-compile compiler:testCompile
test surefire:test
package jar:jar
install install:install
deploy deploy:deploy
4.2.2 POM
POM is the simplest packaging type. The artifact that it generates is itself only, rather than a JAR, SAR,
or EAR. There is no code to test or compile, and there are no resources the process. The default goals for
projects with POM packaging are shown in Table 4.3.
Table 4.3: Default Goals for POM Packaging
Lifecycle Phase Goal
package site:attach-descriptor
install install:install
deploy deploy:deploy

Maven: The Complete Reference 60 / 316
4.2.3 Maven Plugin
This packaging type is similar to JAR packaging type with three additions: plugin:descriptor,
plugin:addPluginArtifactMetadata, and plugin:updateRegistry. These goals gener-
ate a descriptor file and perform some modifications to the repository data. The default goals for projects
with plugin packaging are shown in Table 4.4.
Table 4.4: Default Goals for Plugin Packaging
Lifecycle Phase Goal
generate-resources plugin:descriptor
process-resources resources:resources
compile compiler:compile
process-test-resources resources:testResources
test-compile compiler:testCompile
test surefire:test
package jar:jar, plugin:addPluginArtifactMetadata
install install:install, plugin:updateRegistry
deploy deploy:deploy
4.2.4 EJB
EJBs, or Enterprise Java Beans, are a common data access mechanism for model-driven development in
Enterprise Java. Maven provides support for EJB 2 and 3. Though you must configure the EJB plugin to
specifically package for EJB3, else the plugin defaults to 2.1 and looks for the presence of certain EJB
configuration files. The default goals for projects with EJB packaging are shown in Table 4.5.
Table 4.5: Default Goals for EJB Packaging
Lifecycle Phase Goal
process-resources resources:resources
compile compiler:compile
process-test-resources resources:testResources
test-compile compiler:testCompile
test surefire:test
package ejb:ejb
install install:install
deploy deploy:deploy

Maven: The Complete Reference 61 / 316
4.2.5 WAR
The WAR packaging type is similar to the JAR and EJB types. The exception being the package goal of
war:war. Note that the war:war goal requires a web.xml configuration in your src/main/webapp/WEB-
INF directory. The default goals for projects with WAR packaging are shown in Table 4.6.
Table 4.6: Default Goals for WAR Packaging
Lifecycle Phase Goal
process-resources resources:resources
compile compiler:compile
process-test-resources resources:testResources
test-compile compiler:testCompile
test surefire:test
package war:war
install install:install
deploy deploy:deploy
4.2.6 EAR
EARs are probably the simplest Java EE constructs, consisting primarily of the deployment descriptor
application.xml file, some resources and some modules. The EAR plugin has a goal named generate-
application-xml which generates the application.xml based upon the configuration in the EAR
project’s POM. The default goals for projects with EAR packaging are shown in Table 4.7.
Table 4.7: Default Goals for EAR Packaging
Lifecycle Phase Goal
generate-resources ear:generate-application-xml
process-resources resources:resources
package ear:ear
install install:install
deploy deploy:deploy

Maven: The Complete Reference 62 / 316
4.2.7 Other Packaging Types
This is not an exhaustive list of every packaging type available for Maven. There are a number of pack-
aging formats available through external projects and plugins: the NAR (native archive) packaging type,
the SWF and SWC packaging types for projects that produce Adobe Flash and Flex content, and many
others. You can also define a custom packaging type and customize the default lifecycle goals to suit your
own project packaging requirements.
To use one of these custom packaging types, you need two things: a plugin which defines the lifecycle
for a custom packaging type and a repository which contains this plugin. Some custom packaging types
are defined in plugins available from the central Maven repository. Here is an example of a project which
references the Israfil Flex plugin and uses a custom packaging type of SWF to produce output from Adobe
Flex source.
Custom Packaging Type for Adobe Flex (SWF)
<project>
...
<packaging>swf</packaging>
...
<build>
<plugins>
<plugin>
<groupId>net.israfil.mojo</groupId>
<artifactId>maven-flex2-plugin</artifactId>
<version>1.4-SNAPSHOT</version>
<extensions>true</extensions>
<configuration>
<debug>true</debug>
<flexHome>${flex.home}</flexHome>
<useNetwork>true</useNetwork>
<main>org/sonatype/mavenbook/Main.mxml</main>
</configuration>
</plugin>
</plugins>
</build>
...
</project>
In Section 11.6, we show you how to create your own packaging type with a customized lifecycle. This

Maven: The Complete Reference 63 / 316
example should give you an idea of what you’ll need to do to reference a custom packaging type. All
you need to do is reference the plugin which supplies the custom packaging type. The Israfil Flex plugin
is a third-party Maven plugin hosted at Google Code, for more information about this plugin and how to
use Maven to compile Adobe Flex go to http://code.google.com/p/israfil-mojo. This plugin supplies the
following lifecycle for the SWF packaging type:
Table 4.8: Default Lifecycle for SWF Packaging
Lifecycle Phase Goal
compile flex2:compile-swc
install install:install
deploy deploy:deploy
4.3 Common Lifecycle Goals
Many of the packaging lifecycles have similar goals. If you look at the goals bound to the WAR and
JAR lifecycles, you’ll see that they differ only in the package phase. The package phase of the WAR
lifecycle calls war:war and the package phase of the JAR lifecycle calls jar:jar. Most of the
lifecycles you will come into contact with share some common lifecycle goals for managing resources,
running tests, and compiling source code. In this section, we’ll explore some of these common lifecycle
goals in detail.
4.3.1 Process Resources
The process-resources phase "processes" resources and copies them to the output directory. If you
haven’t customized the default directory locations defined in the Super POM, this means that Maven will
copy the files from ${basedir}/src/main/resources to ${basedir}/target/classes or the directory defined
in ${project.build.outputDirectory}. In addition to copying the resources to the output directory, Maven
can also apply a filter to the resources that allows you to replace tokens within resource file. Just like
variables are referenced in a POM using ${...} notation, you can reference variables in your project’s
resources using the same syntax. Coupled with build profiles, such a facility can be used to produce build
artifacts which target different deployment platforms. This is something that is common in environments
which need to produce output for development, testing, staging, and production platforms from the same
project. For more information about build profiles, see Chapter 5.

Maven: The Complete Reference 64 / 316
To illustrate resource filtering, assume that you have a project with an XML file in src/main/resources/META-
INF/service.xml. You want to externalize some configuration variables to a properties file. In other words,
you might want to reference a JDBC URL, username, and password for your database, and you don’t
want to put these values directly into the service.xml file. Instead, you would like to use a properties
file to capture all of the configuration points for your program. Doing this will allow you to consoli-
date all configuration into a single properties file and make it easier to change configuration values when
you need to target a new deployment environment. First, take a look at the contents of service.xml in
src/main/resources/META-INF.
Using Properties in Project Resources
<service>
<!-- This URL was set by project version ${project.version} -->
<url>${jdbc.url}</url>
<user>${jdbc.username}</user>
<password>${jdbc.password}</password>
</service>
This XML file uses the same property reference syntax you can use in the POM. In fact, the first variable
referenced is the project variable which is also an implicit variable made available in the POM. The
project variable provides access to POM information. The next three variable references are jdbc.
url,jdbc.username, and jdbc.password. These custom variables are defined in a properties file
src/main/filters/default.properties.
default.properties in src/main/filters
jdbc.url=jdbc:hsqldb:mem:mydb
jdbc.username=sa
jdbc.password=
To configure resource filtering with this default.properties file, we need to specify two things in a project’s
POM: a list of properties files in the filters element of the build configuration, and a flag to Maven
that the resources directory is to be filtered. The default Maven behavior is to skip filtering and just copy
the resources to the output directory; you’ll need to explicitly configure resource filter, or Maven will skip
the step altogether. This default ensures that Maven’s resource filtering feature doesn’t surprise you out
of nowhere and clobbering any ${...} references you didn’t want it to replace.
Filter Resources (Replacing Properties)
<build>
<filters>
<filter>src/main/filters/default.properties</filter>
</filters>
<resources>

Maven: The Complete Reference 65 / 316
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
As with all directories in Maven, the resources directory does not need to be in src/main/resources. This is
just the default value defined in the Super POM. You should also note that you don’t need to consolidate all
of your resources into a single directory. You can always separate resources into separate directories under
src/main. Assume that you have a project which contains hundreds of XML documents and hundreds of
images. Instead of mixing the resources in the src/main/resources directory, you might want to create
two directories src/main/xml and src/main/images to hold this content. To add directories to the list of
resource directories, you would add the following resource elements to your build configuration.
Configuring Additional Resource Directories
<build>
...
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
<resource>
<directory>src/main/xml</directory>
</resource>
<resource>
<directory>src/main/images</directory>
</resource>
</resources>
...
</build>
When you are building a project that produces a console application or a command-line tool, you’ll often
find yourself writing simple shell scripts that need to reference the JAR produced by a build. When you are
using the assembly plugin to produce a distribution for an application as a ZIP or TAR, you might place
all of your scripts in a directory like src/main/command. In the following POM resource configuration,
you’ll see how we can use resource filtering and a reference to the project variable to capture the final
output name of the JAR. For more information about the Maven Assembly plugin, see Chapter 8.
Filtering Script Resources
<build>
<groupId>org.sonatype.mavenbook</groupId>
<artifactId>simple-cmd</artifactId>

Maven: The Complete Reference 66 / 316
<version>2.3.1</version>
...
<resources>
<resource>
<filtering>true</filtering>
<directory>${basedir}/src/main/command</directory>
<includes>
<include>run.bat</include>
<include>run.sh</include>
</includes>
<targetPath>${basedir}</targetPath>
</resource>
<resource>
<directory>${basedir}/src/main/resources</directory>
</resource>
</resources>
...
</build>
If you run mvn process-resources in this project, you will end up with two files, run.sh and run.bat, in
${basedir}. We’ve singled out these two files in a resource element, configuring filtering, and set the
targetPath to be ${basedir}. In a second resource element, we’ve configured the default resources
path to be copied to the default output directory without any filtering. Filtering Script Resources shows
you how to declare two resource directories and supply them with different filtering and target directory
preferences. The project from Filtering Script Resources would contain a run.bat file in src/main/com-
mand with the following content:
@echo off
java -jar ${project.build.finalName}.jar %*
After running mvn process-resources, a file named run.bat would appear in ${basedir} with the
following content:
@echo off
java -jar simple-cmd-2.3.1.jar %*
The ability to customize filtering for specific subsets of resources is another reason why complex projects
with many different kinds of resources often find it advantageous to separate resources into multiple
directories. The alternative to storing different kinds of resources with different filtering requirements in
different directories is to use a more complex set of include and exclude patterns to match all resource
files which match a certain pattern.

Maven: The Complete Reference 67 / 316
4.3.2 Compile
Most lifecycles bind the Compiler plugin’s compile goal to the compile phase. This phase calls out
to compile:compile which is configured to compile all of the source code and copy the bytecode to
the build output directory. If you haven’t customized the values defined in the Super POM, compile:
compile is going to compile everything from src/main/java to target/classes. The Compiler plugin
calls out to javac and uses default source and target settings of 1.3 and 1.1. In other words, the compiler
plugin assumes that your Java source conforms to Java 1.3 and that you are targeting a Java 1.1 JVM.
If you would like to change these settings, you’ll need to supply the target and source configuration to
the Compiler plugin in your project’s POM as shown in Setting the Source and Target Versions for the
Compiler Plugin.
Setting the Source and Target Versions for the Compiler Plugin
<project>
...
<build>
...
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
</plugins>
...
</build>
...
</project>
Notice we are configuring the Compiler plugin, and not the specific compile:compile goal. If we
were going to configure the source and target for just the compile:compile goal, we would place the
configuration element below an execution element for the compile:compile goal. We’ve
configured the target and source for the plugin because compile:compile isn’t the only goal we’re
interested in configuring. The Compiler plugin is reused when Maven compiles tests using the comp
ile:testCompile goal, and configuring target and source at the plugin level allows us to define it
once for all goals in a plugin.
If you need to customize the location of the source code, you can do so by changing the build config-
uration. If you wanted to store your project’s source code in src/java instead of src/main/java and if
you wanted build output to go to classes instead of target/classes, you could always override the default
sourceDirectory defined by the Super POM.

Maven: The Complete Reference 68 / 316
Overriding the Default Source Directory
<build>
...
<sourceDirectory>src/java</sourceDirectory>
<outputDirectory>classes</outputDirectory>
...
</build>
Warning
While it might seem necessary to bend Maven to your own idea of project directory structure,
we can’t emphasize enough that you should sacrifice your own ideas of directory structure in
favor of the Maven defaults. This isn’t because we’re trying to brainwash you into accepting the
Maven Way, but it will be easier for people to understand your project if it adheres to the most
basic conventions. Just forget about this. Don’t do it.
4.3.3 Process Test Resources
The process-test-resources phase is almost indistinguishable from the process-resour
ces phase. There are some trivial differences in the POM, but most everything the same. You can filter
test resources just as you filter regular resources. The default location for test resources is defined in the
Super POM as src/test/resources, and the default output directory for test resources is target/test-classes
as defined in ${project.build.testOutputDirectory}.
4.3.4 Test Compile
The test-compile phase is almost identical to the compile phase. The only difference is that
test-compile is going to invoke compile:testCompile to compile source from the test source
directory to the test build output directory. If you haven’t customized the default directories from the
Super POM, compile:testCompile is going to compile the source in src/test/java to the target/test-
classes directory.
As with the source code directory, if you want to customize the location of the test source code and the
output of test compilation, you can do so by overriding the testSourceDirectory and the testOut-
putDirectory. If you wanted to store test source in src-test/ instead of src/test/java and you wanted to save
test bytecode to classes-test/ instead of target/test-classes, you would use the following configuration.

Maven: The Complete Reference 69 / 316
Overriding the Location of Test Source and Output
<build>
...
<testSourceDirectory>src-test</testSourceDirectory>
<testOutputDirectory>classes-test</testOutputDirectory>
...
</build>
4.3.5 Test
Most lifecycles bind the test goal of the Surefire plugin to the test phase. The Surefire plugin is Maven’s
unit testing plugin, the default behavior of Surefire is to look for all classes ending in *Test in the test
source directory and to run them as JUnit tests. The Surefire plugin can also be configured to run TestNG
unit tests.
After running mvn test, you should also notice that the Surefire produces a number of reports in
target/surefire-reports. This reports directory will have two files for each test executed by the Surefire
plugin: an XML document containing execution information for the test, and a text file containing the
output of the unit test. If there is a problem during the test phase and a unit test has failed, you can use
the output of Maven and the contents of this directory to track down the cause of a test failure. This
surefire-reports/ directory is also used during site generation to create an easy to read summary of all the
unit tests in a project.
If you are working on a project that has some failing unit tests, but you want the project to produce output,
you’ll need to configure the Surefire plugin to continue a build even if it encounters a failure. The default
behavior is to stop a build whenever a unit test failure is encountered. To override this behavior, you’ll
need to set the testFailureIgnore configuration property on the Surefire plugin to true.
Configuring Surefire to Ignore Test Failures
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<testFailureIgnore>true</testFailureIgnore>
</configuration>
</plugin>
...
</plugins>

Maven: The Complete Reference 70 / 316
</build>
If you would like to skip tests altogether, you can do so by executing the following command:
$ mvn install -Dmaven.test.skip=true
The maven.test.skip variable controls both the Compiler and the Surefire plugin, if you pass in
maven.test.skip you’ve told Maven to ignore tests altogether.
4.3.6 Install
The install goal of the Install plugin is almost always bound to the install lifecycle phase. This
install:install goal simply installs a project’s main artifact to the local repository. If you have a
project with a groupId of org.sonatype.mavenbook, an artifactId of simple-test, and
aversion of 1.0.2, the install:install goal is going to copy the JAR file from target/simple-
test-1.0.2.jar to ~/.m2/repository/org/sonatype/mavenbook/simple-test/1.0.2/simple-test-1.0.2.jar. If the
project has POM packaging, this goal will copy the POM to the local repository.
4.3.7 Deploy
The deploy goal of the Deploy plugin is usually bound to the deploy lifecycle phase. This phase
is used to deploy an artifact to a remote Maven repository, this is usually required to update a remote
repository when you are performing a release. The deployment procedure can be as simple as copying
a file to another directory or as complex as transferring a file over SCP using a public key. Deployment
settings usually involve credentials to a remote repository, and, as such, deployment settings are usually
not stored in a pom.xml. Instead, deployment settings are more frequently found in an individual user’s
~/.m2/settings.xml. For now, all you need to know is that the deploy:deploy goal is bound to the
deploy phase and it takes care of transporting an artifact to a published repository and updating any
repository information which might be affected by such a deployment.

Maven: The Complete Reference 71 / 316
Chapter 5
Build Profiles
5.1 What Are They For?
Profiles allow for the ability to customize a particular build for a particular environment; profiles enable
portability between different build environments.
What do we mean by different build environments? Two example build environments are production and
development. When you are working in a development environment, your system might be configured to
read from a development database instance running on your local machine while in production, your sys-
tem is configured to read from the production database. Maven allows you to define any number of build
environments (build profiles) which can override any of the settings in the pom.xml. You could configure
your application to read from your local, development instance of a database in your "development" pro-
file, and you can configure it to read from the production database in the "production" profile. Profiles can
also be activated by the environment and platform, you can customize a build to run differently depending
the Operating System or the installed JDK version. Before we talk about using and configuring Maven
profiles, we need to define the concept of Build Portability.
5.1.1 What is Build Portability
A build’s "portability" is a measure of how easy it is to take a particular project and build it in different
environments. A build which works without any custom configuration or customization of properties files

Maven: The Complete Reference 72 / 316
is more portable than a build which requires a great deal of work to build from scratch. The most portable
projects tend to be widely used open source projects like Apache Commons or Apache Velocity which
ship with Maven builds which require little or no customization. Put simply, the most portable project
builds tend to just work, out of the box, and the least portable builds require you to jump through hoops
and configure platform specific paths to locate build tools. Before we show you how to achieve build
portability, let’s survey the different kinds of portability we are talking about.
5.1.1.1 Non-Portable Builds
The lack of portability is exactly what all build tools are made to prevent - however, any tool can be
configured to be non-portable (even Maven). A non-portable project is buildable only under a specific
set of circumstances and criteria (e.g., your local machine). Unless you are working by yourself and you
have no plans on ever deploying your application to another machine, it is best to avoid non-portability
entirely. A non-portable build only runs on a single machine, it is a "one-off". Maven is designed to
discourage non-portable builds by offering the ability to customize builds using profiles.
When a new developer gets the source for a non-portable project, they will not be able to build the project
without rewriting large portions of a build script.
5.1.1.2 Environment Portability
A build exhibits environment portability if it has a mechanism for customizing behavior and configuration
when targeting different environments. A project that contains a reference to a test database in a test
environment, for example, and a production database in a production environment, is environmentally
portable. It is likely that this build has a different set of properties for each environment. When you move
to a different environment, one that is not defined and has no profile created for it, the project will not
work. Hence, it is only portable between defined environments.
When a new developer gets the source for an environmentally portable project, they will have to run the
build within a defined environment or they will have to create a custom environment to successfully build
the project.
5.1.1.3 Organizational (In-House) Portability
The center of this level of portability is a project’s requirement that only a select few may access internal
resources such as source control or an internally-maintained Maven repository. A project at a large corpo-

Maven: The Complete Reference 73 / 316
ration may depend on a database available only to in-house developers, or an open source project might
require a specific level of credentials to publish a web site and deploy the products of a build to a public
repository.
If you attempt to build an in-house project from scratch outside of the in-house network (for example,
outside of a corporate firewall), the build will fail. It may fail because certain required custom plugins
are unavailable, or project dependencies cannot be found because you don’t have the appropriate creden-
tials to retrieve dependencies from a custom remote repository. Such a project is portable only across
environments in a single organization.
5.1.1.4 Wide (Universal) Portability
Anyone may download a widely portable project’s source, compile, and install it without customizing a
build for a specific environment. This is the highest level of portability; anything less requires extra work
for those who wish to build your project. This level of portability is especially important for open source
projects, which depend on the ability for would-be contributors to easily download and build from source.
Any developer could download the source for a widely portable project.
5.1.2 Selecting an Appropriate Level of Portability
Clearly, you’ll want to avoid creating the worst-case scenario: the non-portable build. You may have had
the misfortune to work or study at an organization that had critical applications with non-portable builds.
In such organizations, you cannot deploy an application without the help of a specific individual on a
specific machine. In such an organization, it is also very difficult to introduce new project dependencies
or changes without coordinating the change with the single person who maintains such a non-portable
build. Non-portable builds tend to grow in highly political environments when one individual or group
needs to exert control over how and when a project is built and deployed. "How do we build the system?
Oh, we’ve got to call Jack and ask him to build it for us, no one else deploys to production." That is
a dangerous situation which is more common that you would think. If you work for this organization,
Maven and Maven profiles provide a way out of this mess.
On the opposite end of the portability spectrum are widely portable builds. Widely portable builds are
generally the most difficult build systems to attain. These builds restrict your dependencies to those
projects and tools that may be freely distributed and are publicly available. Many commercial software
packages might be excluded from the most-portable builds because they cannot be downloaded before you
have accepted a certain license. Wide portability also restricts dependencies to those pieces of software
that may be distributed as Maven artifacts. For example, if you depend upon Oracle JDBC drivers, your

Maven: The Complete Reference 74 / 316
users will have to download and install them manually; this is not widely portable as you will have to
distribute a set of environment setup instructions for people interested in building your application. On
the other hand, you could use a JDBC driver which is available from the public Maven repositories like
MySQL or HSQLDB.
As stated previously, open source projects benefit from having the most widely portable build possible.
Widely portable builds reduce the inefficiencies associated with contributing to a project. In an open
source project (such as Maven) there are two distinct groups: end-users and developers. When an end-user
uses a project like Maven and decides to contribute a patch to Maven, they have to make the transition from
using the output of a build to running a build. They have to first become a developer, and if it is difficult
to learn how to build a project, this end-user has a disincentive to take the time to contribute to a project.
In a widely portable project, an end-user doesn’t have to follow a set of arcane build instructions to start
becoming a developer, they can download the source, modify the source, build, and submit a contribution
without asking someone to help them set up a build environment. When the cost of contributing source
back to an open-source project is lower, you’ll see an increase in source code contributions, especially
casual contributions which can make the difference between a project’s success and a project’s failure.
One side-effect of Maven’s adoption across a wide group of open source projects is that it has made it
easier for developers to contribute code to various open source projects.
5.2 Portability through Maven Profiles
A profile in Maven is an alternative set of configuration values which set or override default values. Using
a profile, you can customize a build for different environments. Profiles are configured in the pom.xml
and are given an identifier. Then you can run Maven with a command-line flag that tells Maven to execute
goals in a specific profile. The following pom.xml uses a production profile to override the default
settings of the Compiler plugin.
Using a Maven Profile to Override Production Compiler Settings
<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</groupId>
<artifactId>simple</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>simple</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>

Maven: The Complete Reference 75 / 316
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<profiles> v
1
<profile>
<id>production</id> v
2
<build> v
3
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</ ←-
groupId>
<artifactId>maven-compiler-plugin</ ←-
artifactId>
<configuration>
<debug>false</debug> v
4
<optimize>true</optimize>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
In this example, we’ve added a profile named production that overrides the default configuration of
the Maven Compiler plugin. Let’s examine the syntax of this profile in detail.
v
1The profiles element is in the pom.xml, it contains one or more profile elements. Since
profiles override the default settings in a pom.xml, the profiles element is usually listed as the
last element in a pom.xml.
v
2Each profile has to have an id element. This id element contains the name which is used to invoke
this profile from the command-line. A profile is invoked by passing the -P<profile_id>
command-line argument to Maven.
v
3Aprofile element can contain many of the elements which can appear under the project
element of a POM XML Document. In this example, we’re overriding the behavior of the Compiler
plugin and we have to override the plugin configuration which is normally enclosed in a build
and a plugins element.
v
4We’re overriding the configuration of the Maven Compiler plugin. We’re making sure that the
bytecode produced by the production profile doesn’t contain debug information and that the byte-
code has gone through the compiler’s optimization routines.

Maven: The Complete Reference 76 / 316
To execute mvn install under the production profile, you need to pass the -Pproduction
argument on the command-line. To verify that the production profile overrides the default Compiler
plugin configuration, execute Maven with debug output enabled (-X) as follows:
~/examples/profile $ mvn clean install -Pproduction -X
... (omitting debugging output) ...
[DEBUG] Configuring mojo ’o.a.m.plugins:maven-compiler-plugin:2.0.2: ←-
testCompile’
[DEBUG] (f) basedir = ~\examples\profile
[DEBUG] (f) buildDirectory = ~\examples\profile\target
...
[DEBUG] (f) compilerId = javac
[DEBUG] (f) *debug = false*
[DEBUG] (f) failOnError = true
[DEBUG] (f) fork = false
[DEBUG] (f) *optimize = true*
[DEBUG] (f) outputDirectory = \
~\svnw\sonatype\examples\profile\target\test-classes
[DEBUG] (f) outputFileName = simple-1.0-SNAPSHOT
[DEBUG] (f) showDeprecation = false
[DEBUG] (f) showWarnings = false
[DEBUG] (f) staleMillis = 0
[DEBUG] (f) verbose = false
[DEBUG] -- end configuration --
... (omitting debugging output) ...
This excerpt from the debug output of Maven shows the configuration of the Compiler plugin under the
production profile. As shown in the output, debug is set to false and optimize is set to true.
5.2.1 Overriding a Project Object Model
While the previous example showed you how to override the default configuration properties of a single
Maven plugin, you still don’t know exactly what a Maven profile is allowed to override. The short-answer
to that question is that a Maven profile can override almost everything that you would have in a pom.xml.
The Maven POM contains an element under project called profiles containing a project’s alternate
configurations, and under this element are profile elements which define each profile. Each profile must
have an id, and other than that, it can contain almost any of the elements one would expect to see under
project. The following XML document shows all of the elements, a profile is allowed to override.
Elements Allowed in a Profile
<project>
<profiles>

Maven: The Complete Reference 77 / 316
<profile>
<build>
<defaultGoal>...</defaultGoal>
<finalName>...</finalName>
<resources>...</resources>
<testResources>...</testResources>
<plugins>...</plugins>
</build>
<reporting>...</reporting>
<modules>...</modules>
<dependencies>...</dependencies>
<dependencyManagement>...</dependencyManagement>
<distributionManagement>...</distributionManagement>
<repositories>...</repositories>
<pluginRepositories>...</pluginRepositories>
<properties>...</properties>
</profile>
</profiles>
</project>
A profile can override an element shown with ellipses. A profile can override the final name of a project’s
artifact in a profile, the dependencies, and the behavior of a project’s build via plugin configuration. A
profile can also override the configuration of distribution settings depending on the profile; for example,
if you need to publish an artifact to a staging server in a staging profile, you would create a staging profile
which overrides the distributionManagement element in a profile.
5.3 Profile Activation
In the previous section we showed you how to create a profile that overrides default behavior for a specific
target environment. In the previous build the default build was designed for development and the produc
tion profile exists to provide configuration for a production environment. What happens when you need
to provide customizations based on variables like operating systems or JDK version? Maven provides a
way to "activate" a profile for different environmental parameters, this is called profile activation.
Take the following example, assume that we have a Java library that has a specific feature only available
in the Java 6 release: the Scripting Engine as defined in JSR-223. You’ve separated the portion of the
library that deals with the scripting library into a separate Maven project, and you want people running
Java 5 to be able to build the project without attempting to build the Java 6 specific library extension. You
can do this by using a Maven profile that adds the script extension module to the build only when the
build is running within a Java 6 JDK. First, let’s take a look at our project’s directory layout and how we
want developers to build the system.

Maven: The Complete Reference 78 / 316
When someone runs mvn install with a Java 6 JDK, you want the build to include the simple-
script project’s build, when they are running in Java 5, you would like to skip the simple-script
project build. If you failed to skip the simple-script project build in Java 5, your build would fail
because Java 5 does not have the ScriptEngine on the classpath. Let’s take a look at the library
project’s pom.xml:
Dynamic Inclusion of Submodules Using Profile Activation
<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</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>
<profiles>
<profile>
<id>jdk16</id>
<activation> v
1
<jdk>1.6</jdk>
</activation>
<modules> v
2
<module>simple-script</module>
</modules>
</profile>
</profiles>
</project>
If you run mvn install under Java 1.6, you will see Maven descending into the simple-script subdi-
rectory to build the simple-script project. If you are running mvn install in Java 1.5, the build
will not try to build the simple-script submodule. Exploring this activation configuration in more
detail:

Maven: The Complete Reference 79 / 316
v
1The activation element lists the conditions for profile activation. In this example, we’ve
specified that this profile will be activated by Java versions that begin with "1.6". This would
include "1.6.0_03", "1.6.0_02", or any other string that began with "1.6". Activation parameters
are not limited to Java version, for a full list of activation parameters, see Section 5.3.1.
v
2In this profile we are adding the module simple-script. Adding this module will cause Maven
to look in the simple-script/ subdirectory for a pom.xml.
5.3.1 Activation Configuration
Activations can contain one of more selectors including JDK versions, Operating System parameters,
files, and properties. A profile is activated when all activation criteria has been satisfied. For example,
a profile could list an Operating System family of Windows, and a JDK version of 1.4, this profile will
only be activated when the build is executed on a Windows machine running Java 1.4. If the profile is
active then all elements override the corresponding project-level elements as if the profile were included
with the -P command-line argument. The following example, lists a profile which is activated by a very
specific combination of operating system parameters, properties, and a JDK version.
Profile Activation Parameters: JDK Version, OS Parameters, and Properties
<project>
...
<profiles>
<profile>
<id>dev</id>
<activation>
<activeByDefault>false</activeByDefault> v
1
<jdk>1.5</jdk> v
2
<os>
<name>Windows XP</name> v
3
<family>Windows</family>
<arch>x86</arch>
<version>5.1.2600</version>
</os>
<property>
<name>customProperty</name> v
4
<value>BLUE</value>
</property>
<file>
<exists>file2.properties</exists> v
5
<missing>file1.properties</missing>
</file>
</activation>
...
</profile>

Maven: The Complete Reference 80 / 316
</profiles>
</project>
This previous example defines a very narrow set of activation parameters. Let’s examine each activation
criterion in detail:
v
1The activeByDefault element controls whether this profile is considered active by default.
v
2This profile will only be active for JDK versions that begin with "1.5". This includes "1.5.0_01",
"1.5.1".
v
3This profile targets a very specific version of Windows XP, version 5.1.2600 on a 32-bit platform.
If your project uses the native plugin to build a C program, you might find yourself writing projects
for specific platforms.
v
4The property element tells Maven to activate this profile if the property customProperty
is set to the value BLUE.
v
5The file element allows us to activate a profile based on the presence (or absence) of files. The
dev profile will be activated if a file named file2.properties exists in the base directory of the
project. The dev profile will only be activated if there is no file named file1.properties file in the
base directory of the project.
5.3.2 Activation by the Absence of a Property
You can activate a profile based on the value of a property like environment.type. You can ac-
tivate a development profile if environment.type equals dev, or a production profile if
environment.type equals prod. You can also activate a profile in the absence of a property. The
following configuration activates a profile if the property environment.type is not present during
Maven execution.
Activating Profiles in the Absence of a Property
<project>
...
<profiles>
<profile>
<id>development</id>
<activation>
<property>
<name>!environment.type</name>
</property>

Maven: The Complete Reference 81 / 316
</activation>
</profile>
</profiles>
</project>
Note the exclamation point prefixing the property name. The exclamation point is often referred to as the
"bang" character and signifies "not". This profile is activated when no ${environment.type} property is
set.
5.4 Listing Active Profiles
Maven profiles can be defined in either pom.xml,profiles.xml,~/.m2/settings.xml, or ${M2_HOME}/conf/settings.xml.
With these four levels, there’s no good way of keeping track of profiles available to a particular project
without remembering which profiles are defined in these four files. To make it easier to keep track of
which profiles are available, and where they have been defined, the Maven Help plugin defines a goal,
active-profiles, which lists all the active profiles and where they have been defined. You can run
the active-profiles goal, as follows:
$ mvn help:active-profiles
Active Profiles for Project ’My Project’:
The following profiles are active:
- my-settings-profile (source: settings.xml)
- my-external-profile (source: profiles.xml)
- my-internal-profile (source: pom.xml)
5.5 Tips and Tricks
Profiles can encourage build portability. If your build needs subtle customizations to work on different
platforms or if you need your build to produce different results for different target platforms, project
profiles increase build portability. Settings profiles generally decrease build portability by adding extra-
project information that must be communicated from developer to developer. The following sections
provide some guidelines and some ideas for applying Maven profiles to your project.

Maven: The Complete Reference 82 / 316
5.5.1 Common Environments
One of the core motivations for Maven project profiles was to provide for environment-specific configura-
tion settings. In a development environment, you might want to produce bytecode with debug information
and you might want to configure your system to use a development database instance. In a production
environment you might want to produce a signed JAR and configure the system to use a production
database. In this chapter, we defined a number of environments with identifiers like dev and prod. A
simpler way to do this would be to define profiles that are activated by environment properties and to use
these common environment properties across all of your projects.
For example, if every project had a development profile activated by a property named environm
ent.type having a value of dev, and if those same projects had a production profile activated by a
property named environment.type having a value of prod, you could simply pass in the appropriate
property value on the command-line to ensure that your builds target the correct environment. You can
then use this property to activate profiles defined in a project’s pom.xml as follows. Let’s take a look
at how a project’s pom.xml would define a profile activated by environment.type having the value
dev.
Project Profile Activated by setting environment.type to dev
<project>
...
<profiles>
<profile>
<id>development</id>
<activation>
<activeByDefault>true</activeByDefault>
<property>
<name>environment.type</name>
<value>dev</value>
</property>
</activation>
<properties>
<database.driverClassName>com.mysql.jdbc.Driver</database. ←-
driverClassName>
<database.url>
jdbc:mysql://localhost:3306/app_dev
</database.url>
<database.user>development_user</database.user>
<database.password>development_password</database.password ←-
>
</properties>
</profile>
<profile>
<id>production</id>
<activation>

Maven: The Complete Reference 83 / 316
<property>
<name>environment.type</name>
<value>prod</value>
</property>
</activation>
<properties>
<database.driverClassName>com.mysql.jdbc.Driver</database. ←-
driverClassName>
<database.url>jdbc:mysql://master01:3306,slave01:3306/ ←-
app_prod</database.url>
<database.user>prod_user</database.user>
</properties>
</profile>
</profiles>
</project>
This project defines some properties like database.url and database.user which might be used
to configure another Maven plugin configured in the pom.xml. There are plugins available that can manip-
ulate the database, run SQL, and plugins like the Maven Hibernate3 plugin which can generate annotated
model objects for use in persistence frameworks. A few of these plugins, can be configured in a pom.xml
using these properties. These properties could also be used to filter resources. If we needed to target the
development environment, we would just run the following command:
~/examples/profiles $ mvn install
Because the development profile is active by default, and because there are no other profiles activated,
running mvn help:active-profiles will show that the development profile is active. Now, the
activeByDefault option will only work if no other profiles are active. If you wanted to be sure that the
development profile would be active for a given build, you could explicitly pass in the environment.type
variable as follows:
~/examples/profiles $ mvn install -Denvironment.type=dev
Alternatively, if we need to activate the production profile, we could always run Maven with:
~/examples/profiles $ mvn install -Denvironment.type=prod
To test which profiles are active for a given build, use mvn help:active-profiles.

Maven: The Complete Reference 84 / 316
5.5.2 Protecting Secrets
This best practice builds upon the previous section. In Project Profile Activated by setting environ-
ment.type to dev, the production profile does not contain the database.password property. I’ve
done this on purpose to illustrate the concept of putting secrets in you user-specific settings.xml. If you
were developing an application at a large organization which values security, it is likely that the majority
of the development group will not know the password to the production database. In an organization that
draws a bold line between the development group and the operations group, this will be the norm. Devel-
opers may have access to a development and a staging environment, but they might not have (or want to
have) access to the production database. There are a number of reasons why this makes sense, particu-
larly if an organization is dealing with extremely sensitive financial, intelligence, or medical information.
In this scenario, the production environment build may only be carried out by a lead developer or by a
member of the production operations group. When they run this build using the prod environment.
type, they will need to define this variable in their settings.xml as follows:
Storing Secrets in a User-specific Settings Profile
<settings>
<profiles>
<profile>
<activeByDefault>true</activeByDefault>
<properties>
<environment.type>prod</environment.type>
<database.password>m1ss10nimp0ss1bl3</database.password>
</properties>
</profile>
</profiles>
</settings>
This user has defined a default profile which sets the environment.type to prod and which also
sets the production password. When the project is executed, the production profile is activated by the
environment.type property and the database.password property is populated. This way, you
can put all of the production-specific configuration into a project’s pom.xml and leave out only the single
secret necessary to access the production database.
Note
Secrets usually conflict with wide portability, but this makes sense. You wouldn’t want to share your
secrets openly.

Maven: The Complete Reference 85 / 316
5.5.3 Platform Classifiers
Let’s assume that you have a library or a project that produces platform-specific customizations. Even
though Java is platform-neutral, there are times when you might need to write some code that invokes
platform-specific native code. Another possibility is that you’ve written some C code which is compiled
by the Maven Native plugin and you want to produce a qualified artifact depending on the build platform.
You can set a classifier with the Maven Assembly plugin or with the Maven Jar plugin. The following
pom.xml produces a qualified artifact using profiles which are activated by Operating System parameters.
For more information about the Maven Assembly plugin, see Chapter 8.
Qualifying Artifacts with Platform Activated Project Profiles
<project>
...
<profiles>
<profile>
<id>windows</id>
<activation>
<os>
<family>windows</family>
</os>
</activation>
<build>
<plugins>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<classifier>win</classifier>
</configuration>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>linux</id>
<activation>
<os>
<family>unix</family>
</os>
</activation>
<build>
<plugins>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<classifier>linux</classifier>
</configuration>

Maven: The Complete Reference 86 / 316
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
If the Operating System is in the Windows family, this pom.xml qualifies the JAR artifact with "-win".
If the Operating System is in the Unix family, the artifact is qualified with "-linux". This pom.xml suc-
cessfully adds the qualifiers to the artifacts, but it is more verbose than it need to be due to the redundant
configuration of the Maven Jar plugin in both profiles. This example could be rewritten to use variable
substitution to minimize redundancy as follows:
Qualifying Artifacts with Platform Activated Project Profiles and Variable Substitution
<project>
...
<build>
<plugins>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<classifier>${envClassifier}</classifier>
</configuration>
</plugin>
</plugins>
</build>
...
<profiles>
<profile>
<id>windows</id>
<activation>
<os>
<family>windows</family>
</os>
</activation>
<properties>
<envClassifier>win</envClassifier>
</properties>
</profile>
<profile>
<id>linux</id>
<activation>
<os>
<family>unix</family>
</os>
</activation>

Maven: The Complete Reference 87 / 316
<properties>
<envClassifier>linux</envClassifier>
</properties>
</profile>
</profiles>
</project>
In this pom.xml, each profile doesn’t need to include a build element to configure the Jar plugin. Instead,
each profile is activated by the Operating System family and sets the envClassifier property to either
win or linux. This envClassifier is then referenced in the default pom.xml build element to add
a classifier to the project’s JAR artifact. The JAR artifact will be named ${finalName}-${envClassifier}.jar
and included as a dependency using the following dependency syntax:
Depending on a Qualified Artifact
<dependency>
<groupId>com.mycompany</groupId>
<artifactId>my-project</artifactId>
<version>1.0</version>
<classifier>linux</classifier>
</dependency>
5.6 Summary
When used judiciously, profiles can make it very easy to customize a build for different platforms. If
something in your build needs to define a platform-specific path for something like an application server,
you can put these configuration points in a profile which is activated by an operating system parameter.
If you have a project which needs to produce different artifacts for different environments, you can cus-
tomize the build behavior for different environments and platforms via profile-specific plugin behavior.
Using profiles, builds can become portable, there is no need to rewrite your build logic to support a new
environment, just override the configuration that needs to change and share the configuration points which
can be shared.

Maven: The Complete Reference 88 / 316
Chapter 6
Running Maven
This chapter focuses on the various ways in which Maven can be customized at runtime. It also provides
some documentation of special features such as the ability to customize the behavior of the Maven Reactor
and how to use the Maven Help plugin to obtain information about plugins and plugin goals.
6.1 Maven Command Line Options
The following sections detail Maven’s command line options.
6.1.1 Defining Properties
To define a property use the following option on the command line:
-D, --define <arg>
Defines a system property
This is the option most frequently used to customized the behavior of Maven plugins. Some examples of
using the -D command line argument:

Maven: The Complete Reference 89 / 316
$ mvn help:describe -Dcmd=compiler:compile
$ mvn install -Dmaven.test.skip=true
Properties defined on the command line are also available as properties to be used in a Maven POM or
Maven Plugin. Form more information about referencing Maven properties, see Chapter 9.
Properties can also be used to activate build profiles. For more information about Maven build profiles,
see Chapter 5.
6.1.2 Getting Help
To list the available command line parameters, use the following command line option:
-h, --help
Display help information
Executing Maven with this option produces the following output:
$ mvn --help
usage: mvn [options] [<goal(s)>] [<phase(s)>]
Options:
-am,--also-makeIf project list is specified, also
build projects required by the
list
-amd,--also-make-dependentsIf project list is specified, also
build projects that depend on
projects on the list
-B,--batch-modeRun in non-interactive (batch)
mode
...
If you are looking for information about the goals and parameters available from a specific Maven plugin,
see Section 6.3.

Maven: The Complete Reference 90 / 316
6.1.3 Using Build Profiles
To activate one or more build profiles from the command line, use the following option:
-P, --activate-profiles <arg>
Comma-delimited list of profiles to activate
For more information about build profiles, see Chapter 5.
6.1.4 Displaying Version Information
To display Maven version information, use one of the following options on the command line:
-V, --show-version
Display version information WITHOUT stopping build
-v, --version
Display version information
Both of these options produce the same version information output, but the -v option will terminate the
Maven process after printing out the version. You would use the -V option if you wanted to have the
Maven version information present at the beginning of your build’s output. This can come in handy if you
are running Maven in a continuous build environment and you need to know what version of Maven was
used for a particular build.
Maven Version Information
$ mvn -v
Apache Maven 2.2.1 (r801777; 2009-08-06 14:16:01-0500)
Java version: 1.6.0_15
Java home: /System/Library/Frameworks/JavaVM.framework/Versions/1.6.0/Home
Default locale: en_US, platform encoding: MacRoman
OS name: "mac os x" version: "10.6.1" arch: "x86_64" Family: "mac"

Maven: The Complete Reference 91 / 316
6.1.5 Running in Offline Mode
If you ever need to use Maven without having access to a network, you should use the following option
to prevent any attempt to check for updates to plugins or dependencies over a network:
-o, --offline
Work offline
When running with the offline option enabled, Maven will not attempt to connect to a remote repository
to retrieve artifacts.
6.1.6 Using a Custom POM or Custom Settings File
If you don’t like the pom.xml file name, the location of your user-specific Maven settings, or the default
location of your global settings file, you can customize any of these things with the following options:
-f, --file <file>
Forces the use of an alternate POM file
-s,--settings <arg>
Alternate path for the user settings file
-gs, --global-settings <file>
Alternate path for the global settings file
6.1.7 Encrypting Passwords
The following commands allow you to use Maven to encrypt passwords for storage in a Maven settings
file:
-emp, --encrypt-master-password <password>
Encrypt master security password
-ep, --encrypt-password <password>
Encrypt server password

Maven: The Complete Reference 92 / 316
Encrypting passwords is documented in Section 15.2.11.
6.1.8 Dealing with Failure
The following options control how Maven reacts to a build failure in the middle of a multi-module project
build:
-fae, --fail-at-end
Only fail the build afterwards; allow all non-impacted builds to continue
-ff, --fail-fast
Stop at first failure in reactorized builds
-fn, --fail-never
NEVER fail the build, regardless of project result
The -fn and -fae options are useful options for multi-module builds that are running within a continu-
ous integration tool like Hudson. The -ff option is very useful for developers running interactive builds
who want to have rapid feedback during the development cycle.
6.1.9 Controlling Maven’s Verbosity
If you want to control Maven’s logging level, you can use one of the following three command line
options:
-e, --errors
Produce execution error messages
-X, --debug
Produce execution debug output
-q, --quiet
Quiet output - only show errors
The -q option only prints a message to the output if there is an error or a problem.

Maven: The Complete Reference 93 / 316
The -X option will print an overwhelming amount of debugging log messages to the output. This option is
primarily used by Maven developers and by Maven plugin developers to diagnose problems with Maven
code during development. This -X option is also very useful if you are attempting to diagnose a difficult
problem with a dependency or a classpath.
The -e option will come in handy if you are a Maven developer, or if you need to diagnose an error in a
Maven plugin. If you are reporting an unexpected problem with Maven or a Maven plugin, you will want
to pass both the -X and -e options to your Maven process.
6.1.10 Running Maven in Batch Mode
To run Maven in batch mode use the following option:
-B, --batch-mode
Run in non-interactive (batch) mode
Batch mode is essential if you need to run Maven in a non-interactive, continuous integration environment.
When running in non-interactive mode, Maven will never stop to accept input from the user. Instead, it
will use sensible default values when it requires input.
6.1.11 Downloading and Verifying Dependencies
The following command line options affect the way that Maven will interact with remote repositories and
how it verifies downloaded artifacts:
-C, --strict-checksums
Fail the build if checksums don’t match
-c, --lax-checksums
Warn if checksums don’t match
-U, --update-snapshots
Forces a check for updated releases and snapshots on remote repositories
If you are concerned about security, you will want to run Maven with the -C option. Maven repositories
maintain an MD5 and SHA1 checksum for every artifact stored in a repository. Maven is configured to

Maven: The Complete Reference 94 / 316
warn the end-user if an artifact’s checksum doesn’t match the downloaded artifact. Passing in the -C
option will cause Maven to fail the build if it encounters an artifact with a bad checksum.
The -U option is useful if you want to make sure that Maven is checking for the latest versions of all
SNAPSHOT dependencies.
6.1.12 Non-recursive Builds
There will be times when you simply want to run a Maven build without having Maven descend into all
of a project’s submodules. You can do this by using the following command line option:
-N, --non-recursive
Prevents Maven from building submodules. Only builds the project contained in the current direc-
tory.
Running this will only cause Maven to execute a goal or step through the lifecycle for the project in the
current directory. Maven will not attempt to build all of the projects in a multi-module project when you
use the -N command line option.
6.2 Using Advanced Reactor Options
Starting with the Maven 2.1 release, there are new Maven command line options which allow you to
manipulate the way that Maven will build multimodule projects. These new options are:
-rf, --resume-from
Resume reactor from specified project
-pl, --projects
Build specified reactor projects instead of all projects
-am, --also-make
If project list is specified, also build projects required by the list
-amd, --also-make-dependents
If project list is specified, also build projects that depend on projects on the list

Maven: The Complete Reference 95 / 316
6.2.1 Advanced Reactor Options Example Project
The example in this section is a skeleton of a complex multimodule project that is used to illustrate the
advanced reactor options. While it is possible to read this section without the example code, you might
want to download the example code and follow along, experimenting with the various options as you
learn how to use the advanced reactor options. This section’s example project may be downloaded with
the book’s example code at:
http://www.sonatype.com/books/mvnref-book/mvnref-examples.zip
Unzip this archive in any directory, and then go to the ch-running/ directory. There you will see a direc-
tory named sample-parent/. All of the examples in this section will be executed from the examples/ch-
running/sample-parent/ directory in the examples distribution. The sample-parent/ directory contains the
multimodule project structure shown in Figure 6.1.
Figure 6.1: Directory Structure of Sample Multi-module Project

Maven: The Complete Reference 96 / 316
This project approximates the structure of a real-world enterprise project: the sample-model project
contains a set of foundational model objects used throughout the system, the sample-util project
would contain utility code, the sample-persist project would contain logic that deals with persisting
objects to a database, and the other projects would all be combined to produce the various GUI and Web-
based interfaces that comprise a very complex system. Figure 6.2 captures the dependencies between
each of these sample modules.
Figure 6.2: Dependencies within Sample Multi-module Project
If you go into the sample-parent/ project directory and run mvn clean, you will see that the Maven
Reactor reads all of the project dependencies and comes up with the following build order for these
projects as shown in Order of Project Builds in Maven Reactor.
Order of Project Builds in Maven Reactor
[INFO] Reactor build order:
[INFO] sample-parent
[INFO] sample-model
[INFO] sample-persist
[INFO] sample-services

Maven: The Complete Reference 97 / 316
[INFO] sample-util
[INFO] sample-security
[INFO] sample-admin-webapp
[INFO] sample-webapp
[INFO] sample-rest
[INFO] sample-client-connector
[INFO] sample-gui
[INFO] sample-admin-gui
6.2.2 Resuming Builds
The -rf or --resume-from option can come in handy if you want to tell the Maven Reactor to resume
a build from a particular project. This can be useful if you are working with a large multimodule project
and you want to restart a build at a particular project in the Reactor without running through all of the
projects that precede it in the build order.
Assume that you are working on the multi-module project with the build order shown in Order of Project
Builds in Maven Reactor and that your build ran successfully up until Maven encountered a failing unit
test in sample-client-connector. With the -rf option, you can fix the unit test in simple-cli
ent-connector and then run mvn -rf sample-client-connect from the sample-parent/ di-
rectory to resume the build with the final three projects.
$ mvn --resume-from sample-client-connector install
[INFO] Scanning for projects...
[INFO] Reactor build order:
[INFO] sample-client-connector
[INFO] sample-gui
[INFO] sample-admin-gui
...
6.2.3 Specifying a Subset of Projects
The -pl or --projects option allows you to select a list of projects from a multimodule project. This
option can be useful if you are working on a specific set of projects, and you’d rather not wait for a full
build of a multi-module project during a development cycle.
Assume that you are working on the multi-module project with the build order shown in Order of Project
Builds in Maven Reactor and that you are a developer focused on the sample-rest and sample-

Maven: The Complete Reference 98 / 316
client-connector projects. If you only wanted Maven to build the sample-rest and sample-
client-connector project, you would use the following syntax from the sample-parent/ directory:
$ mvn --projects sample-client-connector,sample-rest install
[INFO] Scanning for projects...
[INFO] Reactor build order:
[INFO] sample-rest
[INFO] sample-client-connector
6.2.4 Making a Subset of Projects
If you wanted to run a portion of the larger build, you would use the -pl or --projects option with
the -am or --also-make option. When you specify a project with the -am option, Maven will
build all of the projects that the specified project depends upon (either directly or indirectly). Maven will
examine the list of projects and walk down the dependency tree, finding all of the projects that it needs to
build.
If you are working on the multi-module project with the build order shown in Order of Project Builds in
Maven Reactor and you were only interested in working on the sample-services project, you would
run mvn -pl simple-services -am to build only those projects
$ mvn --projects sample-services --also-make install
[INFO] Scanning for projects...
[INFO] Reactor build order:
[INFO] sample-parent
[INFO] sample-model
[INFO] sample-persist
[INFO] sample-services
6.2.5 Making Project Dependents
While the -am command makes all of the projects required by a particular project in a multi-module
build, the -amd or --also-make-dependents option configures Maven to build a project and any
project that depends on that project. When using --also-make-dependents, Maven will examine
all of the projects in our reactor to find projects that depend on a particular project. It will automatically
build those projects and nothing else.
If you are working on the multi-module project with the build order shown in Order of Project Builds in
Maven Reactor and you wanted to make sure that your changes to sample-services did not introduce

Maven: The Complete Reference 99 / 316
any errors into the projects that directly or indirectly depend on sample-services, you would run
the following command:
$ mvn --projects sample-services --also-make-dependents install
[INFO] Scanning for projects...
[INFO] Reactor build order:
[INFO] sample-services
[INFO] sample-admin-webapp
[INFO] sample-webapp
[INFO] sample-rest
6.2.6 Resuming a "make" build
When using --also-make, Maven will execute a subset of the larger build as shown in Section 6.2.4.
Combining --project,--also-make, and --resume-from provides you with the ability to refine
your build even further. The -rf or --resume-from resumes the build from a specific point in the
Reactor build order.
$ mvn --projects sample-webapp --also-make \
--resume-from sample-services install
[INFO] Scanning for projects...
[INFO] Reactor build order:
[INFO] sample-services
[INFO] sample-util
[INFO] sample-security
[INFO] sample-webapp
In this example, the build is resumed from sample-services which omits the sample-persist
and sample-model projects from the build. If you are focused on individual components and you
need to accelerate your build times, using these advanced reactor options together is a great way to skip
portions of your large multi-module project build. The --resume-from argument also works with --
also-make-dependents.
6.3 Using the Maven Help Plugin
Throughout this book, we introduce Maven plugins, talking about Maven Project Object Model (POM)
files, settings files, and profiles. There are going to be times when you need a tool to help you make sense
of some of the models that Maven is using and what goals are available on a specific plugin. The Maven

Maven: The Complete Reference 100 / 316
Help plugin allows you to list active Maven profiles, display an effective POM, print the effective settings,
or list the attributes of a Maven plugin.
The Maven Help plugin has four goals. The first three goals — active-profiles,effective-
pom, and effective-settings — describe a particular project and must be run in the base directory
of a project. The last goal — describe — is slightly more complex, showing you information about a
plugin or a plugin goal. The following commands provide some general information about the four goals:
help:active-profiles
Lists the profiles (project, user, global) which are active for the build.
help:effective-pom
Displays the effective POM for the current build, with the active profiles factored in.
help:effective-settings
Prints out the calculated settings for the project, given any profile enhancement and the inheritance
of the global settings into the user-level settings.
help:describe
Describes the attributes of a plugin. This need not run under an existing project directory. You must
at least give the groupId and artifactId of the plugin you wish to describe.
6.3.1 Describing a Maven Plugin
Once you start using Maven, you’ll spend most of your time trying to get more information about Maven
Plugins: How do plugins work? What are the configuration parameters? What are the goals? The help:
describe goal is something you’ll be using very frequently to retrieve this information. With the
plugin parameter you can specify a plugin you wish to investigate, passing in either the plugin prefix
(e.g. maven-help-plugin as help) or the groupId:artifact[:version], where version
is optional. For example, the following command uses the Help plugin’s describe goal to print out
information about the Maven Help plugin.
$ mvn help:describe -Dplugin=help
...
Group Id: org.apache.maven.plugins
Artifact Id: maven-help-plugin
Version: 2.0.1
Goal Prefix: help
Description:
The Maven Help plugin provides goals aimed at helping to make sense
out of the build environment. It includes the ability to view the
effective POM and settings files, after inheritance and active

Maven: The Complete Reference 101 / 316
profiles have been applied, as well as a describe a particular plugin
goal to give usage information. ...
Executing the describe goal with the plugin parameter printed out the Maven coordinates for the
plugin, the goal prefix, and a brief description of the plugin. While this information is helpful, you’ll
usually be looking for more detail than this. If you want the Help plugin to print a full list of goals with
parameters, execute the help:describe goal with the parameter full as follows:
$ mvn help:describe -Dplugin=help -Dfull
...
Group Id: org.apache.maven.plugins
Artifact Id: maven-help-plugin
Version: 2.0.1
Goal Prefix: help
Description:
The Maven Help plugin provides goals aimed at helping to make sense
out of the build environment. It includes the ability to view the
effective POM and settings files, after inheritance and active
profiles have been applied, as well as a describe a particular plugin
goal to give usage information.
Mojos:
Goal: ’active-profiles’
Description:
Lists the profiles which are currently active for this build.
Implementation: org.apache.maven.plugins.help.ActiveProfilesMojo
Language: java
Parameters:
[0] Name: output
Type: java.io.File
Required: false
Directly editable: true
Description:
This is an optional parameter for a file destination for the output of
this mojo...the listing of active profiles per project.
[1] Name: projects
Type: java.util.List
Required: true
Directly editable: false

Maven: The Complete Reference 102 / 316
Description:
This is the list of projects currently slated to be built by Maven.
This mojo doesn’t have any component requirements.
... removed the other goals ...
This option is great for discovering all of a plugin’s goals as well as their parameters. But sometimes this
is far more information than necessary. To get information about a single goal, set the mojo parameter as
well as the plugin parameter. The following command lists all of the information about the Compiler
plugin’s compile goal.
$ mvn help:describe -Dplugin=compiler -Dmojo=compile -Dfull

Maven: The Complete Reference 103 / 316
Chapter 7
Maven Configuration
7.1 Configuring Maven Plugins
To customize the behavior of a Maven Plugin, you will need to configure the plugin in a project’s POM.
The following sections outline the various methods available for customizing a Maven plugin’s configu-
ration.
7.1.1 Plugin Configuration Parameters
Maven plugins are configured using properties that are defined by goals within a plugin. If you look at a
goal like the compile goal in the Maven Compiler Plugin you will see a list of configuration parameters
like source,target,compilerArgument,fork,optimize, and many others. If you look at
the testCompile goal you will see a different list of configuration parameters for the testCompile
goal. If you are looking for details on the available plugin goal configuration parameters, you can use the
Maven Help Plugin to describe a particular plugin or a particular plugin goal.
To describe a particular plugin, use the help:describe goal from the command line as follows:
$ mvn help:describe -Dcmd=compiler:compile
[INFO] [help:describe {execution: default-cli}]
[INFO] ’compiler:compile’ is a plugin goal (aka mojo).
Mojo: ’compiler:compile’

Maven: The Complete Reference 104 / 316
compiler:compile
Description: Compiles application sources
Deprecated. No reason given
For more information about the available configuration parameters, run the same command with the -
Ddetail argument:
$ mvn help:describe -Dcmd=compiler:compile -Ddetail
[INFO] [help:describe {execution: default-cli}]
[INFO] ’compiler:compile’ is a plugin goal (aka mojo).
Mojo: ’compiler:compile’
compiler:compile
Description: Compiles application sources
Deprecated. No reason given
Implementation: org.apache.maven.plugin.CompilerMojo
Language: java
Bound to phase: compile
Available parameters:
compilerArgument
Sets the unformatted argument string to be passed to the compiler if fork
is set to true.
This is because the list of valid arguments passed to a Java compiler
varies based on the compiler version.
Deprecated. No reason given
compilerArguments
Sets the arguments to be passed to the compiler (prepending a dash) if
fork is set to true.
This is because the list of valid arguments passed to a Java compiler
varies based on the compiler version.
Deprecated. No reason given
compilerId (Default: javac)
The compiler id of the compiler to use. See this guide for more
information.
Deprecated. No reason given
compilerVersion
Version of the compiler to use, ex. ’1.3’, ’1.5’, if fork is set to true.
Deprecated. No reason given
debug (Default: true)
Set to true to include debugging information in the compiled class files.
Deprecated. No reason given

Maven: The Complete Reference 105 / 316
encoding
The -encoding argument for the Java compiler.
Deprecated. No reason given
excludes
A list of exclusion filters for the compiler.
Deprecated. No reason given
executable
Sets the executable of the compiler to use when fork is true.
Deprecated. No reason given
failOnError (Default: true)
Indicates whether the build will continue even if there are compilation
errors; defaults to true.
Deprecated. No reason given
fork (Default: false)
Allows running the compiler in a separate process. If ’false’ it uses the
built in compiler, while if ’true’ it will use an executable.
Deprecated. No reason given
includes
A list of inclusion filters for the compiler.
Deprecated. No reason given
maxmem
Sets the maximum size, in megabytes, of the memory allocation pool, ex.
’128’, ’128m’ if fork is set to true.
Deprecated. No reason given
meminitial
Initial size, in megabytes, of the memory allocation pool, ex. ’64’,
’64m’ if fork is set to true.
Deprecated. No reason given
optimize (Default: false)
Set to true to optimize the compiled code using the compiler’s
optimization methods.
Deprecated. No reason given
outputFileName
Sets the name of the output file when compiling a set of sources to a
single file.
Deprecated. No reason given
showDeprecation (Default: false)
Sets whether to show source locations where deprecated APIs are used.

Maven: The Complete Reference 106 / 316
Deprecated. No reason given
showWarnings (Default: false)
Set to true to show compilation warnings.
Deprecated. No reason given
source
The -source argument for the Java compiler.
Deprecated. No reason given
staleMillis (Default: 0)
Sets the granularity in milliseconds of the last modification date for
testing whether a source needs recompilation.
Deprecated. No reason given
target
The -target argument for the Java compiler.
Deprecated. No reason given
verbose (Default: false)
Set to true to show messages about what the compiler is doing.
Deprecated. No reason given
If you need to get a list of plugin goals which are contained in a plugin, you can run the help:describe
goal and pass in the plugin parameter. The plugin parameter accepts a plugin prefix or a groupId and
an artifactId for a plugin as shown in the following examples:
$ mvn help:describe -Dplugin=compiler
[INFO] [help:describe {execution: default-cli}]
[INFO] org.apache.maven.plugins:maven-compiler-plugin:2.0.2
Name: Maven Compiler Plugin
Description: Maven Plugins
Group Id: org.apache.maven.plugins
Artifact Id: maven-compiler-plugin
Version: 2.0.2
Goal Prefix: compiler
This plugin has 2 goals:
compiler:compile
Description: Compiles application sources
Deprecated. No reason given
compiler:testCompile
Description: Compiles application test sources
Deprecated. No reason given

Maven: The Complete Reference 107 / 316
You can use the groupId and the artifactId of the plugin and get the same list of plugin goals.
$ mvn help:describe -Dplugin=org.apache.maven.plugins:maven-compiler- ←-
plugin
Passing the -Ddetail argument to the help:describe goal with the plugin parameter will cause
Maven to print out all of the goals and all of the goal parameters for the entire plugin.
7.1.2 Adding Plugin Dependencies
If you need to configure a plugin to use specific versions of dependencies, you can define these depen-
dencies under a dependencies element under plugin. When the plugin executes, it will execute with a
classpath that contains these dependencies. Adding Dependencies to a Plugin is an example of a plugin
configuration that overrides default dependency versions and adds new dependencies to facilitate goal
execution.
Adding Dependencies to a Plugin
<plugin>
<groupId>com.agilejava.docbkx</groupId>
<artifactId>docbkx-maven-plugin</artifactId>
<version>2.0.9</version>
<dependencies>
<dependency>
<groupId>docbook</groupId>
<artifactId>docbook-xml</artifactId>
<version>4.5</version>
</dependency>
<dependency>
<groupId>org.apache.fop</groupId>
<artifactId>fop-pdf-images</artifactId>
<version>1.3</version>
</dependency>
<dependency>
<groupId>org.apache.fop</groupId>
<artifactId>fop-pdf-images-res</artifactId>
<version>1.3</version>
<classifier>res</classifier>
</dependency>
<dependency>
<groupId>pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>0.7.4-dev</version>
<classifier>dev</classifier>

Maven: The Complete Reference 108 / 316
</dependency>
</dependencies>
</plugin>
7.1.3 Setting Global Plugin Parameters
To set a value for a plugin configuration parameter in a particular project, use the XML shown in Con-
figuring a Maven Plugin. Unless this configuration is overridden by a more specific plugin parameter
configuration, Maven will use the values defined directly under the plugin element for all goals which
are executed in this plugin.
Configuring a Maven Plugin
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
7.1.4 Setting Execution Specific Parameters
You can configure plugin parameters for specific executions of a plugin goal. Setting Configuration
Parameters in an Execution shows an example of configuration parameters being passed to the execution
of the run goal of the AntRun plugin during the validate phase. This specific execution will inherit the
configuration parameters from the plugin’s configuration element and merge them with the values defined
for this particular execution.
Setting Configuration Parameters in an Execution
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>run</goal>

Maven: The Complete Reference 109 / 316
</goals>
<configuration>
<tasks>
<echo>${PATH}=${env.PATH}</echo>
<echo>User’s Home Directory: ${user.home}</echo>
<echo>Project’s Base Director: ${basedir}</echo>
</tasks>
</configuration>
</execution>
</executions>
</plugin>
7.1.5 Setting Default Command Line Execution Parameters
Starting with Maven 2.2.0, you can now supply configuration parameters for goals which are executed
from the command-line. To do this, use the special execution id value of "default-cli". Configuring Plugin
Parameters for Command Line Execution shows an example that binds the single goal to the package
phase of the lifecycle which produces a binary distribution. This example also configures the default-
cli execution for the assembly plugin to use the jar-with-dependencies assembly descriptor.
The bin.xml descriptor will be used during the lifecycle, and jar-with-dependencies will be used
when you execute mvn assembly:assembly from the command line.
Configuring Plugin Parameters for Command Line Execution
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<appendAssemblyId>false</appendAssemblyId>
</configuration>
<executions>
<execution>
<id>assemble-binary</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptors>
<descriptor>src/main/assembly/bin.xml</descriptor>
</descriptors>
</configuration>
</execution>
<execution>
<id>default-cli</id>

Maven: The Complete Reference 110 / 316
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</execution>
</executions>
</plugin>
7.1.6 Setting Parameters for Goals Bound to Default Lifecycle
Starting with Maven 2.2.0, if you need to customize the behavior of a goal which is already bound to the
default lifecycle, you can use the execution id "default-<goal>". You can customize the behavior of the
Jar plugin’s jar goal which is bound to the package phase in the default lifecycle, and you can customize
the configuration parameters of a separate goal execution if you follow the example shown in Setting a
Parameter for a Default Goal Execution.
Setting a Parameter for a Default Goal Execution
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<id>default-jar</id>
<configuration>
<excludes>
<exclude>**/somepackage/*</exclude>
</excludes>
</configuration>
</execution>
<execution>
<id>special-jar</id>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<includes>
<include>**/sompackage/*</include>
</includes>
<classifier>somepackage</classifier>
</configuration>
</execution>
</executions>

Maven: The Complete Reference 111 / 316
</plugin>
In this example, the default jar goal is customized to exclude contents in a specific package. Another jar
goal is bound to the package phase to create a JAR file which contains only the contents of a particular
package in a classified JAR file.
Configuring the default goal execution parameters can also come in handy if you need to configure two
goals bound to the default lifecycle with separate settings for the same configuration parameter. Set-
ting Two Default Goal Plugin Configuration Parameters shows an example that configures the default re-
sources:resources goal to exclude empty directories while configuring the default resources:testResources
goal to include empty directories.
Setting Two Default Goal Plugin Configuration Parameters
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>default-resources</id>
<configuration>
<includeEmptyDirs>false</includeEmptyDirs>
</configuration>
</execution>
<execution>
<id>default-testResources</id>
<configuration>
<includeEmptyDirs>true</includeEmptyDirs>
</configuration>
</execution>
</executions>
</plugin>

Maven: The Complete Reference 112 / 316
Chapter 8
Maven Assemblies
8.1 Introduction
Maven provides plugins that are used to create the most common archive types, most of which are con-
sumable as dependencies of other projects. Some examples include the JAR, WAR, EJB, and EAR plug-
ins. As discussed in Chapter 4these plugins correspond to different project packaging types each with a
slightly different build process. While Maven has plugins and customized lifecycles to support standard
packaging types, there are times when you’ll need to create an archive or directory with a custom layout.
Such custom archives are called Maven Assemblies.
There are any number of reasons why you may want to build custom archives for your project. Perhaps
the most common is the project distribution. The word ‘distribution’ means many different things to
different people (and projects), depending on how the project is meant to be used. Essentially, these
are archives that provide a convenient way for users to install or otherwise make use of the project’s
releases. In some cases, this may mean bundling a web application with an application server like Jetty.
In others, it could mean bundling API documentation alongside source and compiled binaries like jar
files. Assemblies usually come in handy when you are building the final distribution of a product. For
example, products like Nexus introduced in Repository Management with Nexus, are the product of large
multi-module Maven products, and the final archive you download from Sonatype was created using a
Maven Assembly.
In most cases, the Assembly plugin is ideally suited to the process of building project distributions. How-
ever, assemblies don’t have to be distribution archives; assemblies are intended to provide Maven users

Maven: The Complete Reference 113 / 316
with the flexibility they need to produce customized archives of all kinds. Essentially, assemblies are in-
tended to fill the gaps between the standard archive formats provided by project package types. Of course,
you could write an entire Maven plugin simply to generate your own custom archive format, along with
a new lifecycle mapping and artifact-handling configuration to tell Maven how to deploy it. But the As-
sembly plugin makes this unnecessary in most cases by providing generalized support for creating your
own archive recipe without spending so much time writing Maven code.
8.2 Assembly Basics
Before we go any further, it’s best to take a minute and talk about the two main goals in the Assembly
plugin: assembly:assembly, and the single mojo. I list these two goals in different ways because
it reflects the difference in how they’re used. The assembly:assembly goal is designed to be invoked
directly from the command line, and should never be bound to a build lifecycle phase. In contrast, the
single mojo is designed to be a part of your everyday build, and should be bound to a phase in your
project’s build lifecycle.
The main reason for this difference is that the assembly:assembly goal is what Maven terms an
aggregator mojo; that is, a mojo which is designed to run at most once in a build, regardless of how many
projects are being built. It draws its configuration from the root project - usually the top-level POM or
the command line. When bound to a lifecycle, an aggregator mojo can have some nasty side-effects. It
can force the execution of the package lifecycle phase to execute ahead of time, and can result in builds
which end up executing the package phase twice.
Because the assembly:assembly goal is an aggregator mojo, it raises some issues in multi-module
Maven builds, and it should only be called as a stand-alone mojo from the command-line. Never bind an
assembly:assembly execution to a lifecycle phase. assembly:assembly was the original goal
in the Assembly plugin, and was never designed to be part of the standard build process for a project. As
it became clear that assembly archives were a legitimate requirement for projects to produce, the single
mojo was developed. This mojo assumes that it has been bound to the correct part of the build process, so
that it will have access to the project files and artifacts it needs to execute within the lifecycle of a large
multi-module Maven project. In a multi-module environment, it will execute as many times as it is bound
to the different module POMs. Unlike assembly:assembly,single will never force the execution
of another lifecycle phase ahead of itself.
The Assembly plugin provides several other goals in addition to these two. However, discussion of these
other mojos is beyond the scope of this chapter, because they serve exotic or obsolete use cases, and
because they are almost never needed. Whenever possible, you should definitely stick to using assem
bly:assembly for assemblies generated from the command line, and to single for assemblies bound
to lifecycle phases.

Maven: The Complete Reference 114 / 316
8.2.1 Predefined Assembly Descriptors
While many people opt to create their own archive recipes - called assembly descriptors - this isn’t strictly
necessary. The Assembly plugin provides built-in descriptors for several common archive types that you
can use immediately without writing a line of configuration. The following assembly descriptors are
predefined in the Maven Assembly plugin:
bin
The bin descriptor is used to bundle project LICENSE,README, and NOTICE files with the
project’s main artifact, assuming this project builds a jar as its main artifact. Think of this as the
smallest possible binary distribution for completely self-contained projects.
jar-with-dependencies
The jar-with-dependencies descriptor builds a JAR archive with the contents of the main
project jar along with the unpacked contents of all the project’s runtime dependencies. Coupled
with an appropriate Main-Class Manifest entry (discussed in “Plugin Configuration” below),
this descriptor can produce a self-contained, executable jar for your project, even if the project has
dependencies.
project
The project descriptor simply archives the project directory structure as it exists in your file-
system and, most likely, in your version control system. Of course, the target directory is omitted,
as are any version-control metadata files like the CVS and .svn directories we’re all used to seeing.
Basically, the point of this descriptor is to create a project archive that, when unpacked, can be built
using Maven.
src
The src descriptor produces an archive of your project source and pom.xml files, along with any
LICENSE,README, and NOTICE files that are in the project’s root directory. This precursor to the
project descriptor produces an archive that can be built by Maven in most cases. However, because
of its assumption that all source files and resources reside in the standard src directory, it has the
potential to leave out non-standard directories and files that are nonetheless critical to some builds.
8.2.2 Building an Assembly
The Assembly plugin can be executed in two ways: you can invoke it directly from the command line, or
you can configure it as part of your standard build process by binding it to a phase of your project’s build
lifecycle. Direct invocation has its uses, particularly for one-off assemblies that are not considered part of
your project’s core deliverables. In most cases, you’ll probably want to generate the assemblies for your
project as part of its standard build process. Doing this has the effect of including your custom assemblies

Maven: The Complete Reference 115 / 316
whenever the project is installed or deployed into Maven’s repositories, so they are always available to
your users.
As an example of the direct invocation of the Assembly plugin, imagine that you wanted to ship off a
copy of your project which people could build from source. Instead of just deploying the end-product of
the build, you wanted to include the source as well. You won’t need to do this often, so it doesn’t make
sense to add the configuration to your POM. Instead, you can use the following command:
$ mvn -DdescriptorId=project assembly:single
...
[INFO] [assembly:single]
[INFO] Building tar : /Users/~/mvn-examples-1.0/assemblies/direct- ←-
invocation/\
target/direct-invocation-1.0-SNAPSHOT-project.tar.gz
[INFO] Building tar : /Users/~/mvn-examples-1.0/assemblies/direct- ←-
invocation/\
target/direct-invocation-1.0-SNAPSHOT-project.tar.bz2
[INFO] Building zip: /Users/~/mvn-examples-1.0/assemblies/direct- ←-
invocation/\
target/direct-invocation-1.0-SNAPSHOT-project.zip
...
Imagine you want to produce an executable JAR from your project. If your project is totally self-contained
with no dependencies, this can be achieved with the main project artifact using the archive configuration of
the JAR plugin. However, most projects have dependencies, and those dependencies must be incorporated
in any executable JAR. In this case, you want to make sure that every time the main project JAR is installed
or deployed, your executable JAR goes along with it.
Assuming the main class for the project is org.sonatype.mavenbook.App, the following POM
configuration will create an executable JAR:
Assembly Descriptor for Executable JAR
<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.assemblies</groupId>
<artifactId>executable-jar</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Assemblies Executable Jar Example</name>
<url>http://sonatype.com/book</url>
<dependencies>

Maven: The Complete Reference 116 / 316
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.4</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2-beta-2</version>
<executions>
<execution>
<id>create-executable-jar</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptorRefs>
<descriptorRef>
jar-with-dependencies
</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>org.sonatype.mavenbook.App ←-
</mainClass>
</manifest>
</archive>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
There are two things to notice about the configuration above. First, we’re using the descriptorRefs
configuration section instead of the descriptorId parameter we used last time. This allows multiple
assembly types to be built from the same Assembly plugin execution, while still supporting our use case
with relatively little extra configuration. Second, the archive element under configuration sets
the Main-Class manifest attribute in the generated JAR. This section is commonly available in plugins
that create JAR files, such as the JAR plugin used for the default project package type.
Now, you can produce the executable JAR simply by executing mvn package. Afterward, we’ll also

Maven: The Complete Reference 117 / 316
get a directory listing for the target directory, just to verify that the executable JAR was generated. Finally,
just to prove that we actually do have an executable JAR, we’ll try executing it:
$ mvn package
... (output omitted) ...
[INFO] [jar:jar]
[INFO] Building jar: ~/mvn-examples-1.0/assemblies/executable-jar/target/\
executable-jar-1.0-SNAPSHOT.jar
[INFO] [assembly:single {execution: create-executable-jar}]
[INFO] Processing DependencySet (output=)
[INFO] Building jar: ~/mvn-examples-1.0/assemblies/executable-jar/target/\
executable-jar-1.0-SNAPSHOT-jar-with-dependencies.jar
... (output omitted) ...
$ ls -1 target
... (output omitted) ...
executable-jar-1.0-SNAPSHOT-jar-with-dependencies.jar
executable-jar-1.0-SNAPSHOT.jar
... (output omitted) ...
$ java -jar \
target/executable-jar-1.0-SNAPSHOT-jar-with-dependencies.jar
Hello, World!
From the output shown above, you can see that the normal project build now produces a new artifact in
addition to the main JAR file. The new one has a classifier of jar-with-dependencies. Finally, we
verified that the new JAR actually is executable, and that executing the JAR produced the desired output
of “Hello, World!”
8.2.3 Assemblies as Dependencies
When you generate assemblies as part of your normal build process, those assembly archives will be
attached to your main project’s artifact. This means they will be installed and deployed alongside the main
artifact, and are then resolvable in much the same way. Each assembly artifact is given the same basic
coordinates (groupId,artifactId, and version) as the main project. However, these artifacts
are attachments, which in Maven means they are derivative works based on some aspect of the main
project build. To provide a couple of examples, source assemblies contain the raw inputs for the project
build, and jar-with-dependencies assemblies contain the project’s classes plus its dependencies.
Attached artifacts are allowed to circumvent the Maven requirement of one project, one artifact precisely
because of this derivative quality.
Since assemblies are (normally) attached artifacts, each must have a classifier to distinguish it from the
main artifact, in addition to the normal artifact coordinates. By default, the classifier is the same as the
assembly descriptor’s identifier. When using the built-in assembly descriptors, as above, the assembly

Maven: The Complete Reference 118 / 316
descriptor’s identifier is generally also the same as the identifier used in the descriptorRef for that
type of assembly.
Once you’ve deployed an assembly alongside your main project artifact, how can you use that assembly
as a dependency in another project? The answer is fairly straightforward. Projects depend on other
projects using a combination of four basic elements, referred to as a project’s coordinates: groupId,
artifactId,version, and packaging. In Section 5.5.3, multiple platform-specific variants of a
project’s artifact are available, and the project specifies a classifier element with a value of either
win or linux to select the appropriate dependency artifact for the target platform. Assembly artifacts
can be used as dependencies using the required coordinates of a project plus the classifier under which
the assembly was installed or deployed. If the assembly is not a JAR archive, we also need to declare its
type.
8.2.4 Assembling Assemblies via Assembly Dependencies
Configuring the project assembly in top-level POM
<project>
...
<build>
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2-beta-2</version>
<executions>
<execution>
<id>create-project-bundle</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptorRefs>
<descriptorRef>project</descriptorRef>
</descriptorRefs>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
</build>
...

Maven: The Complete Reference 119 / 316
</project>
Each project POM references the managed plugin configuration from Configuring the project assembly in
top-level POM using a minimal plugin declaration in its build section shown in Activating the Assembly
Plugin Configuration in Child Projects.
Activating the Assembly Plugin Configuration in Child Projects
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
</plugin>
</plugins>
</build>
To produce the set of project assemblies, run mvn install from the top-level directory. You should
see Maven installing artifacts with classifiers in your local repository.
$ mvn install
...
Installing ~/mvn-examples-1.0/assemblies/as-dependencies/project-parent/\
second-project/target/second-project-1.0-SNAPSHOT-project.tar.gz to
~/.m2/repository/org/sonatype/mavenbook/assemblies/second-project/1.0- ←-
SNAPSHOT/\
second-project-1.0-SNAPSHOT-project.tar.gz
...
Installing ~/mvn-examples-1.0/assemblies/as-dependencies/project-parent/\
second-project/target/second-project-1.0-SNAPSHOT-project.tar.bz2 to
~/.m2/repository/org/sonatype/mavenbook/assemblies/second-project/1.0- ←-
SNAPSHOT/\
second-project-1.0-SNAPSHOT-project.tar.bz2
...
Installing ~/mvn-examples-1.0/assemblies/as-dependencies/project-parent/\
second-project/target/second-project-1.0-SNAPSHOT-project.zip to
~/.m2/repository/org/sonatype/mavenbook/assemblies/second-project/1.0- ←-
SNAPSHOT/\\
second-project-1.0-SNAPSHOT-project.zip
...
When you run install, Maven will copy each project’s main artifact and each assembly to your local Maven
repository. All of these artifacts are now available for reference as dependencies in other projects locally.
If your ultimate goal is to create a bundle which includes assemblies from multiple projects, you can do so
by creating another project which will include other project’s assemblies as dependencies. This bundling

Maven: The Complete Reference 120 / 316
project (aptly named project-bundle) is responsible for creating the bundled assembly. The POM for the
bundling project would resemble the XML document listed in POM for the Assembly Bundling Project.
POM for the Assembly Bundling Project
<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.assemblies</groupId>
<artifactId>project-bundle</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>Assemblies-as-Dependencies Example Project Bundle</name>
<url>http://sonatype.com/book</url>
<dependencies>
<dependency>
<groupId>org.sonatype.mavenbook.assemblies</groupId>
<artifactId>first-project</artifactId>
<version>1.0-SNAPSHOT</version>
<classifier>project</classifier>
<type>zip</type>
</dependency>
<dependency>
<groupId>org.sonatype.mavenbook.assemblies</groupId>
<artifactId>second-project</artifactId>
<version>1.0-SNAPSHOT</version>
<classifier>project</classifier>
<type>zip</type>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2-beta-2</version>
<executions>
<execution>
<id>bundle-project-sources</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptorRefs>
<descriptorRef>
jar-with-dependencies
</descriptorRef>

Maven: The Complete Reference 121 / 316
</descriptorRefs>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
This bundling project’s POM references the two assemblies from first-project and second-pro
ject. Instead of referencing the main artifact of each project, the bundling project’s POM specifies a
classifier of project and a type of zip. This tells Maven to resolve the ZIP archive which was created
by the project assembly. Note that the bundling project generates a jar-with-dependencies
assembly. jar-with-dependencies does not create a particularly elegant bundle, it simply creates
a JAR file with the unpacked contents of all of the dependencies. jar-with-dependencies is really
just telling Maven to take all of the dependencies, unpack them, and then create a single archive which
includes the output of the current project. In this project, it has the effect of creating a single JAR file that
puts the two project assemblies from first-project and second-project side-by-side.
This example illustrates how the basic capabilities of the Maven Assembly plugin can be combined with-
out the need for a custom assembly descriptor. It achieves the purpose of creating a single archive
that contains the project directories for multiple projects side-by-side. This time, the jar-with-
dependencies is just a storage format, so we don’t need to specify a Main-Class manifest attribute.
To build the bundle, we just build the project-bundle project normally:
$ mvn package
...
[INFO] [assembly:single {execution: bundle-project-sources}]
[INFO] Processing DependencySet (output=)
[INFO] Building jar: ~/downloads/mvn-examples-1.0/assemblies/as- ←-
dependencies/\
project-bundle/target/project-bundle-1.0-SNAPSHOT-jar-with-dependencies. ←-
jar
To verify that the project-bundle assembly contains the unpacked contents of the assembly dependencies,
run jar tf:
$ jar tf \
target/project-bundle-1.0-SNAPSHOT-jar-with-dependencies.jar
...
first-project-1.0-SNAPSHOT/pom.xml
first-project-1.0-SNAPSHOT/src/main/java/org/sonatype/mavenbook/App.java
first-project-1.0-SNAPSHOT/src/test/java/org/sonatype/mavenbook/AppTest. ←-
java
...

Maven: The Complete Reference 122 / 316
second-project-1.0-SNAPSHOT/pom.xml
second-project-1.0-SNAPSHOT/src/main/java/org/sonatype/mavenbook/App.java
second-project-1.0-SNAPSHOT/src/test/java/org/sonatype/mavenbook/AppTest. ←-
java
After reading this section, the title should make more sense. You’ve assembled assemblies from two
projects into an assembly using a bundling project which has a dependency on each of the assemblies.
8.3 Overview of the Assembly Descriptor
When the standard assembly descriptors introduced in Section 8.2 are not adequate, you will need to
define your own assembly descriptor. The assembly descriptor is an XML document which defines the
structure and contents of an assembly. The assembly descriptor contains five main configuration sections,
plus two additional sections: one for specifying standard assembly-descriptor fragments, called compo-
nent descriptors, and another for specifying custom file processor classes to help manage the assembly-
production process.
Base Configuration
This section contains the information required by all assemblies, plus some additional configuration
options related to the format of the entire archive, such as the base path to use for all archive entries.
For the assembly descriptor to be valid, you must at least specify the assembly id, at least one
format, and at least one of the other sections shown above.
File Information
The configurations in this segment of the assembly descriptor apply to specific files on the file
system within the project’s directory structure. This segment contains two main sections: files
and fileSets. You use files and fileSets to control the permissions of files in an assembly
and to include or exclude files from an assembly.
Dependency Information
Almost all projects of any size depend on other projects. When creating distribution archives,
project dependencies are usually included in the end-product of an assembly. This section manages
the way dependencies are included in the resulting archive. This section allows you to specify
whether dependencies are unpacked, added directly to the lib/ directory, or mapped to new file
names. This section also allows you to control the permissions of dependencies in the assembly,
and which dependencies are included in an assembly.
Repository Information
At times, it’s useful to isolate the sum total of all artifacts necessary to build a project, whether
they’re dependency artifacts, POMs of dependency artifacts, or even a project’s own POM ances-
try (your parent POM, its parent, and so on). This section allows you to include one or more

Maven: The Complete Reference 123 / 316
artifact-repository directory structures inside your assembly, with various configuration options.
The Assembly plugin does not have the ability to include plugin artifacts in these repositories yet.
Module Information
This section of the assembly descriptor allows you to take advantage of these parent-child relation-
ships when assembling your custom archive, to include source files, artifacts, and dependencies
from your project’s modules. This is the most complex section of the assembly descriptor, because
it allows you to work with modules and sub-modules in two ways: as a series of fileSets (via
the sources section) or as a series of dependencySets (via the binaries section).
8.4 The Assembly Descriptor
This section is a tour of the assembly descriptor which contains some guidelines for developing a custom
assembly descriptor. The Assembly plugin is one of the largest plugins in the Maven ensemble, and one
of the most flexible.
8.4.1 Property References in Assembly Descriptors
Any property discussed in Section 9.2 can be referenced in an assembly descriptor. Before any assembly
descriptor is used by Maven, it is interpolated using information from the POM and the current build
environment. All properties supported for interpolation within the POM itself are valid for use in assembly
descriptors, including POM properties, POM element values, system properties, user-defined properties,
and operating-system environment variables.
The only exceptions to this interpolation step are elements in various sections of the descriptor named
outputDirectory,outputDirectoryMapping, or outputFileNameMapping. The reason
these are held back in their raw form is to allow artifact- or module-specific information to be applied
when resolving expressions in these values, on a per-item basis. <!--This last paragraph is not clear.-→
8.4.2 Required Assembly Information
There are two essential pieces of information that are required for every assembly: the id, and the list
of archive formats to produce. In practice, at least one other section of the descriptor is required - since
most archive format components will choke if they don’t have at least one file to include - but without at
least one format and an id, there is no archive to create. The id is used both in the archive’s file name,

Maven: The Complete Reference 124 / 316
and as part of the archive’s artifact classifier in the Maven repository. The format string also controls the
archiver-component instance that will create the final assembly archive. All assembly descriptors must
contain an id and at least one format:
Required Assembly Descriptor Elements
<assembly>
<id>bundle</id>
<formats>
<format>zip</format>
</formats>
...
</assembly>
The assembly id can be any string that does not contain spaces. The standard practice is to use dashes
when you must separate words within the assembly id. If you were creating an assembly to create an
interesting unique package structure, you would give your an id of something like interesting-
unique-package. It also supports multiple formats within a single assembly descriptor, allowing
you to create the familiar .zip,.tar.gz, and .tar.bz2 distribution archive set with ease. If you don’t find
the archive format you need, you can also create a custom format. Custom formats are discussed in
Section 8.5.8. The Assembly plugin supports several archive formats natively, including:
• jar
• zip
• tar
• bzip2
• gzip
• tar.gz
• tar.bz2
• rar
• war
• ear
• sar
• dir

Maven: The Complete Reference 125 / 316
The id and format are essential because they will become a part of the coordinates for the assembled
archive. The example from Required Assembly Descriptor Elements will create an assembly artifact of
type zip with a classifier of bundle.
8.5 Controlling the Contents of an Assembly
In theory, id and format are the only absolute requirements for a valid assembly descriptor; however,
many assembly archivers will fail if they do not have at least one file to include in the output archive.
The task of defining the files to be included in the assembly is handled by the five main sections of the
assembly descriptor: files,fileSets,dependencySets,repositories, and moduleSets.
To explore these sections most effectively, we’ll start by discussing the most elemental section: files.
Then, we’ll move on to the two most commonly used sections, fileSets and dependencySets.
Once you understand the workings of fileSets and dependencySets, it’s easier to understand
repositories and moduleSets.
8.5.1 Files Section
The files section is the simplest part of the assembly descriptor, it is designed for files that have a
definite location relative to your project’s directory. Using this section, you have absolute control over
the exact set of files that are included in your assembly, exactly what they are named, and where they will
reside in the archive.
Including a JAR file in an Assembly using files
<assembly>
...
<files>
<file>
<source>target/my-app-1.0.jar</source>
<outputDirectory>lib</outputDirectory>
<destName>my-app.jar</destName>
<fileMode>0644</fileMode>
</file>
</files>
...
</assembly>

Maven: The Complete Reference 126 / 316
Assuming you were building a project called my-app with a version of 1.0,Including a JAR file in an
Assembly using files would include your project’s JAR in the assembly’s lib/ directory, trimming the
version from the file name in the process so the final file name is simply my-app.jar. It would then make
the JAR readable by everyone and writable by the user that owns it (this is what the mode 0644 means
for files, using Unix four-digit Octal permission notation). For more information about the format of the
value in fileMode, please see the Wikipedia’s explanation of four-digit Octal notation.
You could build a very complex assembly using file entries, if you knew the full list of files to be included.
Even if you didn’t know the full list before the build started, you could probably use a custom Maven
plugin to discover that list and generate the assembly descriptor using references like the one above.
While the files section gives you fine-grained control over the permission, location, and name of each
file in the assembly archive, listing a file element for every file in a large archive would be a tedious
exercise. For the most part, you will be operating on groups of files and dependencies using fileSets.
The remaining four file-inclusion sections are designed to help you include entire sets of files that match
a particular criteria.
8.5.2 FileSets Section
Similar to the files section, fileSets are intended for files that have a definite location relative to
your project’s directory structure. However, unlike the files section, fileSets describe sets of files,
defined by file and path patterns they match (or don’t match), and the general directory structure in which
they are located. The simplest fileSet just specifies the directory where the files are located:
<assembly>
...
<fileSets>
<fileSet>
<directory>src/main/java</directory>
</fileSet>
</fileSets>
...
</assembly>
This file set simply includes the contents of the src/main/java directory from our project. It takes advan-
tage of many default settings in the section, so let’s discuss those briefly.
First, you’ll notice that we haven’t told the file set where within the assembly matching files should
be located. By default, the destination directory (specified with outputDirectory) is the same as
the source directory (in our case, src/main/java). Additionally, we haven’t specified any inclusion or
exclusion file patterns. When these are empty, the file set assumes that all files within the source directory
are included, with some important exceptions. The exceptions to this rule pertain mainly to source-

Maven: The Complete Reference 127 / 316
control metadata files and directories, and are controlled by the useDefaultExcludes flag, which
is defaulted to true. When active, useDefaultExcludes will keep directories like .svn/ and CVS/
from being added to the assembly archive. Section 8.5.3 provides a detailed list of the default exclusion
patterns.
If we want more control over this file set, we can specify it more explicitly. Including Files with fileSet
shows a fileSet element with all of the default elements specified.
Including Files with fileSet
<assembly>
...
<fileSets>
<fileSet>
<directory>src/main/java</directory>
<outputDirectory>src/main/java</outputDirectory>
<includes>
<include>**</include>
</includes>
<useDefaultExcludes>true</useDefaultExcludes>
<fileMode>0644</fileMode>
<directoryMode>0755</directoryMode>
</fileSet>
</fileSets>
...
</assembly>
The includes section uses a list of include elements, which contain path patterns. These patterns
may contain wildcards such as ‘**’ which matches one or more directories or ‘*’ which matches part of a
file name, and ‘?’ which matches a single character in a file name. Including Files with fileSet uses a
fileMode entry to specify that files in this set should be readable by all, but only writable by the owner.
Since the fileSet includes directories, we also have the option of specifying a directoryMode that
works in much the same way as the fileMode. Since a directories’ execute permission is what allows
users to list their contents, we want to make sure directories are executable in addition to being readable.
Like files, only the owner can write to directories in this set.
The fileSet entry offers some other options as well. First, it allows for an excludes section with
a form identical to the includes section. These exclusion patterns allow you to exclude specific file
patterns from a fileSet. Exclude patterns take precedence over include patterns. Additionally, you
can set the filtering flag to true if you want to substitute property values for expressions within
the included files. Expressions can be delimited either by ${ and }(standard Maven expressions like
${project.groupId}) or by @and @(standard Ant expressions like @project.groupId@). You