Maven: The Complete Reference
11.6. Plugins and the Maven Lifecycle

In the Chapter 4, The Build Lifecycle chapter, you learned that lifecycles can be customized by packaging types. A plugin can both introduce a new packaging type and customize the lifecycle. In this section, you are going to learn how you can customize the lifecycle from a custom Maven plugin. You are going to learn how to execute a parallel lifecycle.
Let’s assume you write some goal that depends on the output from a
previous build. Maybe the ZipMojo goal can only run if there is
output to include in an archive. You can specify something like a
prerequisite goal by using the @execute annotation on a Mojo
class. This annotation will cause Maven to spawn a parallel build and
execute a goal or a lifecycle in a parallel instance of Maven that
isn’t going to affect the current build.
- @execute goal="<goal>"
-
This will execute the given goal before execution of this one. The
goal name is specified using the
prefix:goalnotation. - @execute phase="<phase>"
- This will fork an alternate build lifecycle up to the specified phase before continuing to execute the current one. If no lifecycle is specified, Maven will use the lifecycle of the current build.
- @execute lifecycle="<lifecycle>" phase="<phase>"
- This will execute the given alternate lifecycle. A custom lifecycle can be defined in META-INF/maven/lifecycles.xml.
A custom lifecycle must be packaged in the plugin under the
META-INF/maven/lifecycles.xml file. You can include a lifecycle
under src/main/resources in META-INF/maven/lifecycles.xml. The
following lifecycle.xml declares a lifecycle named zipcycle that
contains only the zip goal in a package phase.
Define a Custom Lifecycle in lifecycles.xml.
<lifecycles>
<lifecycle>
<id>zipcycle</id>
<phases>
<phase>
<id>package</id>
<executions>
<execution>
<goals>
<goal>zip</goal>
</goals>
</execution>
</executions>
</phase>
</phases>
</lifecycle>
</lifecycles>
If you wanted to execute the zipcycle lifecycle within another
build, you could then create a ZipForkMojo which uses the @execute
annotation to tell Maven to step through the zipcycle lifecycle when
the ZipForkMojo is executed.
Forking a Custom Lifecycle from a Mojo.
/**
* Forks a zip lifecycle.
* @goal zip-fork
* @execute lifecycle="zipcycle" phase="package"
*/
public class ZipForkMojo extends AbstractMojo
{
public void execute()
throws MojoExecutionException
{
getLog().info( "doing nothing here" );
}
}
Running the ZipForkMojo will fork the lifecycle. If you’ve
configured your plugin to execute with the goal prefix zip, running
zip-fork should produce something similar to the following output.
$ mvn zip:zip-fork [INFO] Scanning for projects... [INFO] Searching repository for plugin with prefix: 'zip'. [INFO] ---------------------------------------------------------------------- [INFO] Building Maven Zip Forked Lifecycle Test [INFO]task-segment: [zip:zip-fork] [INFO] ---------------------------------------------------------------------- [INFO] Preparing zip:zip-fork [INFO] [site:attach-descriptor] [INFO] [zip:zip] [INFO] Building zip: \ ~/maven-zip-plugin/src/projects/zip-lifecycle-test/target/output.zip [INFO] [zip:zip-fork] [INFO] doing nothing here [INFO] --------------------------------------------------------------------- [INFO] BUILD SUCCESSFUL [INFO] --------------------------------------------------------------------- [INFO] Total time: 1 second [INFO] Finished at: Sun Apr 29 16:10:06 CDT 2007 [INFO] Final Memory: 3M/7M [INFO] ---------------------------------------------------------------------
Calling zip-fork spawned another lifecycle, Maven executed the
zipcycle lifecycle then it printed out the message from
ZipFormMojo's execute method.
Once you’ve created your own lifecycle and spawned it from a Mojo. The next question you might have is how do you override the default lifecycle? How do you create custom lifecycles and attach them to projects? In Chapter 4, The Build Lifecycle, we saw that the packaging of a project defines the lifecycle of a project. There’s something different about almost every packaging type; each packaging type attaches different goals to the default lifecycle. When you create a custom lifecycle, you can attach that lifecycle to a packaging type by supplying some Plexus configuration in your plugin’s archive.
To define a new lifecycle for a new packaging type, you’ll need to
configure a LifecycleMapping component in Plexus. In your plugin
project, create a META-INF/plexus/components.xml under
src/main/resources. In components.xml add the content from
Overriding the Default Lifecycle. Set the name of the packaging type under
role-hint, and the set of phases containing the coordinates of the
goals to bind (omit the version). Multiple goals can be associated
with a phase using a comma delimited list.
Overriding the Default Lifecycle.
<component-set>
<components>
<component>
<role>org.apache.maven.lifecycle.mapping.LifecycleMapping</role>
<role-hint>zip</role-hint>
<implementation>
org.apache.maven.lifecycle.mapping.DefaultLifecycleMapping
</implementation>
<configuration>
<phases>
<process-resources>
org.apache.maven.plugins:maven-resources-plugin:resources
</process-resources>
<compile>
org.apache.maven.plugins:maven-compiler-plugin:compile
</compile>
<package>org.sonatype.mavenbook.plugins:maven-zip-plugin:zip</package>
</phases>
</configuration>
</component>
</components>
</component-set>
If you create a plugin which defines a new packaging type and a customized lifecycle, Maven won’t know anything about it until you add the plugin to your project’s POM and set the extensions element to true. Once you do this, Maven will scan your plugin for more than just Mojos to execute, it will look for the components.xml under META-INF/plexus, and it will make the packaging type available to your project.
Configuring a Plugin as an Extension.
<project>
...
<build>
...
<plugins>
<plugin>
<groupId>com.training.plugins</groupId>
<artifactId>maven-zip-plugin</artifactId>
<extensions>true</extensions>
</plugin>
</plugins>
</build>
</project>
Once you add the plugin with the extensions element set to true, you can use the custom packaging type and your project will be able to execute the custom lifecycle associated with that packaging type.
