Maven supports the notion of a product with multiple modules. While each project.xml
is a discreet
unit of work, they can be gathered together using the reactor to build simultaneously. The reactor was
originally created to encourage the creation, or refactoring, of projects into smaller,
discrete, more coherent units.
The reactor determines the correct build order from the dependencies stated by each project in their respective project descriptors, and will then execute a stated set of goals. It can be used for both building projects and other goals, such as site generation.
While the reactor requires you to write some Jelly script to interface with it, there is also a friendly
wrapper plugin called multiproject
that can allow you to control the setup with simple properties.
Using the plugin is quite simple. The default set up assumes that you are in the top level directory of your
build, and that and subdirectories that contain a project.xml
file are subprojects to build.
To change this behaviour, set the maven.multiproject.includes
and
maven.multiproject.excludes
properties appropriately, for example:
# Foo is broken, don't build it maven.multiproject.excludes=foo/project.xml
All of the artifact based goals have a multiproject equivalent:
multiproject:install |
Build and install all projects into the local repository |
multiproject:install-snapshot |
Build and install a timestamped build of all projects into the local repository |
multiproject:deploy |
Build and install all projects, deploying to the remote repository |
multiproject:deploy-snapshot |
Build and install a timestamped build of all projects, deploying to the remote repository |
For the plugin to determine how to build each project, you must define a property for each project that requires it:
maven.multiproject.type=war
The default type is jar
.
Note that the original purpose of the Multiproject plugin was to assist in aggregating the web site of subprojects, and so this comprises a large amount of the plugin's functionality. Simply by running:
maven multiproject:site
This goal will build the sites of all subprojects, including the top level that it was run from and will build an appropriate navigation to access each of the subprojects, and an overview listing the subprojects.
The behaviour of this goal and all others can be easily customised. For more information, see the Multiproject plugin reference.
Finally, you may wish to run some other goal(s) over the set of projects. To do this, run the following goal:
maven multiproject:goal -Dgoal=goal1,goal2
While the Multiproject plugin covers most common use cases in a convenient manner, in some instances it is necessary to access the reactor directly to execute multiple projects.
The normal use of the reactor tag is as follows:
<maven:reactor includes="**/project.xml" excludes="" banner="Building" goals="goal1, goal2" ignoreFailures="false" />
This will loop through every project.xml
file found in the current tree, in the order defined
by the dependencies they have on each other. The goals listed will be executed on each project in sequence.
The reactor tag is described in the Maven Jelly Tag Library reference.
In some instances, you will want to work with the projects that the reactor did in your own script afterwards.
To do this, you can utilise the ${reactorProjects}
variable set in the Jelly context after each
reactor execution. This is a list, and so can be iterated. Each variable in the list will be a project object,
and can be used in the same way as ${pom}
would normally be used.
If you'd like to gather a list of subprojects without executing any goals on them, this can be done by using
the collectOnly
attribute of the maven:reactor
tag.
In some cases, you may wish to process a whole set of projects, and handle the failed projects differently.
This requires that you set the ignoreFailures
attribute to true
in the
maven:reactor
tag. After all the projects have finished processing, the context variable
${failedProjects}
will be available to iterate through and projects that failed to build
completely.
If ignoreFailures
is not set, it defaults to false
and the entire build will end
when one project fails to build.