# 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.

### 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.

**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>
                            <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 following:

```
[INFO] Scanning for projects...
[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`.

**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>
                                <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, “Maven Lifecycle Phases”**.

_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 |
| 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
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](http://maven.apache.org/doxia/) document generation and other report generation plugins. You can generate a site from a Maven project by running the following command:

```
$ mvn site
```

### 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.

#### 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, “Default Goals for JAR Packaging”**.

_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, “Default Goals for POM Packaging”**.

_Table 4.3. Default Goals for POM Packaging_

| Lifecycle Phase | Goal |
| --- | --- |
| package | site:attach-descriptor |
| install | install:install |
| deploy | deploy:deploy |

#### 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 generate 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, “Default Goals for Plugin Packaging”**.

_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, “Default Goals for EJB Packaging”**.

_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 |

#### 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, “Default Goals for WAR Packaging”**.

_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, “Default Goals for EAR Packaging”**.

_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 |

#### 4.2.7. Other Packaging Types

This is not an exhaustive list of every packaging type available for Maven. There are a number of packaging 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.

### 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}_.

**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>
```

### 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.

### 4.3.3. Process Test Resources

The `process-test-resources` phase is almost indistinguishable from the `process-resources` phase. There are some trivial differences in the POM, but most everything the same.

### 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.

### 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 unit tests.

### 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.

### 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.
