The Assembly plugin provides enough flexibility to solve many problems in a number of different ways. If you have a unique requirement for your project, there's a good chance that you can use the methods documented in this chapter to achieve almost any assembly structure. This section of the chapter details some common best practices which, if adhered to, will make your experiences with the assembly plugin more productive and less painful.
Up to now, we’ve been talking mainly about one-off solutions for building a particular type of assembly. But what do you do if you have dozens of projects that all need a particular type of assembly? In short, how can we reuse the effort we’ve invested to get our assemblies just the way we like them across more than one project without copying and pasting our assembly descriptor?
The simplest answer is to create a standardized, versioned
artifact out of the assembly descriptor, and deploy it. Once that’s
done, you can specify that the Assembly plugin section of your project’s
POM include the assembly-descriptor artifact as a
plugin-level dependency, which will prompt Maven to resolve and include
that artifact in the plugin’s classpath. At that point, you can use the
assembly descriptor via the descriptorRefs
configuration section in the Assembly plugin declaration. To illustrate,
consider this example assembly descriptor:
<assembly> <id>war-fragment</id> <formats> <format>zip</format> </formats> <includeBaseDirectory>false</includeBaseDirectory> <dependencySets> <dependencySet> <outputDirectory>WEB-INF/lib</outputDirectory> </dependencySet> </dependencySets> <fileSets> <fileSet> <directory>src/main/webapp</directory> <outputDirectory>/</outputDirectory> <excludes> <exclude>**/web.xml</exclude> </excludes> </fileSet> </fileSets> </assembly>
Included in your project, this descriptor would be a useful way to
bundle the project contents so that it could be unpacked directly into
an existing web application in order to add to it (for adding an
extending feature, say). However, if your team builds more than one of
these web-fragment projects, it will likely want to reuse this
descriptor rather than duplicating it. To deploy this descriptor as its
own artifact, we’re going to put it in its own project, under the
src/main/resources/assemblies
directory.
The project structure for this assembly-descriptor artifact will look similar to the following:
|-- pom.xml `-- src `-- main `-- resources `-- assemblies `-- web-fragment.xml
Notice the path of our web-fragment
descriptor
file. By default, Maven includes the files from the
src/main/resources
directory structure in the final
jar, which means our assembly descriptor will be included with no extra
configuration on our part. Also, notice the
assemblies/
path prefix, the Assembly plugin
expects this path prefix on all descriptors provided in the plugin
classpath. It’s important that we put our descriptor in the appropriate
relative location, so it will be picked up by the Assembly plugin as it
executes.
Remember, this project is separate from your actual
web-fragment
project now; the assembly descriptor has
become its own artifact with its own version and, possibly, its own
release cycle. Once you install this new project using Maven, you’ll be
able to reference it in your web-fragment
projects.
For clarity, the build process should look something like this:
$ mvn install
(...)
[INFO] [install:install]
[INFO] Installing (...)/web-fragment-descriptor/target/web-fragment-descriptor-1.0-SNAPSHOT.jar
to /Users/~/.m2/repository/org/sonatype/mavenbook/assemblies/\
web-fragment-descriptor/1.0-SNAPSHOT/web-fragment-descriptor-1.0-SNAPSHOT.jar
[INFO] ---------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ---------------------------------------------------------------
[INFO] Total time: 5 seconds
(...)
Since there are no sources for the
web-fragment-descriptor
project, the resulting jar
artifact will include nothing but our web-fragment
assembly descriptor. Now, let’s use this new descriptor artifact:
<project> (...) <artifactId>my-web-fragment</artifactId> (...) <build> <plugins> <plugin> <artifactId>maven-assembly-plugin</artifactId> <version>2.2-beta-2</version> <dependencies> <dependency> <groupId>org.sonatype.mavenbook.assemblies</groupId> <artifactId>web-fragment-descriptor</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies> <executions> <execution> <id>assemble</id> <phase>package</phase> <goals> <goal>single</goal> </goals> <configuration> <descriptorRefs> <descriptorRef>web-fragment</descriptorRef> </descriptorRefs> </configuration> </execution> </executions> </plugin> (...) </plugins> </build> (...) </project>
Two things are special about this Assembly plugin configuration:
-
We have to include a plugin-level dependency declaration on our new
web-fragment-descriptor
artifact in order to have access to the assembly descriptor via the plugin’s classpath. -
Since we’re using a classpath reference instead of a file in the local project directory structure, we must use the
descriptorRefs
section instead of thedescriptor
section. Also, notice that, while the assembly descriptor is actually in theassemblies/web-fragment.xml
location within the plugin’s classpath, we reference it without theassemblies/
prefix. This is because the Assembly plugin assumes that built-in assembly descriptors will always reside in the classpath under this path prefix.
Now, you’re free to reuse the POM configuration above in as many projects as you like, with the assurance that all of their web-fragment assemblies will turn out the same. As you need to make adjustments to the assembly format - maybe to include other resources, or to fine-tune the dependency and file sets - you can simply increment the version of the assembly descriptor’s project, and release it again. POMs referencing the assembly-descriptor artifact can then adopt this new version of the descriptor as they are able.
One final point about assembly-descriptor reuse: you may want to
consider sharing the plugin configuration itself as well as publishing
the descriptor as an artifact. This is a fairly simple step; you simply
add the configuration listed above to the
pluginManagement
section of your parent
POM, then reference the managed plugin configuration
from your module POM like this:
(...) <build> <plugins> <plugin> <artifactId>maven-assembly-plugin</artifactId> </plugin> (...)
If you’ve added the rest of the plugin’s configuration - listed in
the previous example - to the pluginManagement
section of the project’s parent POM, then each project inheriting from
that parent POM can add a minimal entry like the one
above and take advantage of an advanced assembly format in their own
builds.