Including Module Binaries
Warning
Warning: Using the binaries
section of a moduleSet
definition involves some tricky considerations that are a result of the way Maven sorts and executes project builds within a multimodule context. Please read this FAQ entry if you decide to use them.
NOTE: The new useAllReactorProjects
flag in the moduleSet
section allows you to consume module binaries from child modules in a multimodule build. This is an important to resolve the conflict between Maven's build ordering and the old approach to module binaries, where the assembly was build from the parent POM. Please read the FAQ entry above for more information, and read the documentation below (carefully!) to see the new approach in action.
Introduction
It is common practice to create an assembly using the parent POM of a multimodule build. At times, you may want to ensure that this assembly also includes one or more of the module binaries.
This example demonstrates how to include the artifact and dependencies of a module, under the directory modules/<module-name>
.
The Assembly Descriptor
First, let's write an assembly descriptor to create this assembly. For the sake of clarity, this descriptor will be as simple as possible, only demonstrating the features described by this example.
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.2.0 http://maven.apache.org/xsd/assembly-2.2.0.xsd"> <id>bin</id> <formats> <format>dir</format> </formats> <includeBaseDirectory>false</includeBaseDirectory> <moduleSets> <moduleSet> <!-- Enable access to all projects in the current multimodule build! --> <useAllReactorProjects>true</useAllReactorProjects> <!-- Now, select which projects to include in this module-set. --> <includes> <include>org.test:child1</include> </includes> <binaries> <outputDirectory>modules/maven-assembly-plugin</outputDirectory> <unpack>false</unpack> </binaries> </moduleSet> </moduleSets> </assembly>
This descriptor states that the assembly id should be bin
, that the output format is a directory, and that the contents of the assembly should not be contained within a directory named after the finalName of the top-level project.
Furthermore, it states that we wish to include the artifact files for the module with a groupId of org.test
and an artifactId of child1
, along with its dependency artifacts. These artifacts should be contained within the directory structure modules/child1
for this module, since the outputDirectory expression will be interpolated on a module-by-module basis.
Finally, notice the new useAllReactorProjects
flag. This enables access to all projects in the current reactor (multimodule build), even from a child module. Using this flag, it's now possible to use a child module - sorted to the end of the multimodule build process using appropriate dependency declarations - to generate an assembly containing module binaries.
The POM
Now, let's review the POM configuration necessary to enable the building of this assembly via the assembly:single
goal. First, let's look at the parent POM:
<?xml version="1.0" encoding="UTF-8"?> <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/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.test</groupId> <artifactId>parent</artifactId> <version>1.0</version> <packaging>pom</packaging> <name>Parent</name> <modules> <module>child1</module> <module>child2</module> <module>child3</module> <module>distribution</module> </modules> <build> <pluginManagement> <plugins> <plugin> <artifactId>maven-assembly-plugin</artifactId> <version>3.7.1</version> <configuration> <descriptors> <descriptor>src/assembly/bin.xml</descriptor> </descriptors> </configuration> </plugin> </plugins> </pluginManagement> </build> </project>
NOTE: The last module - distribution
- is the child in which the assembly will be created.
That POM looks like this:
<?xml version="1.0" encoding="UTF-8"?> <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/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.test</groupId> <artifactId>parent</artifactId> <version>1.0</version> </parent> <artifactId>distribution</artifactId> <packaging>pom</packaging> <name>Distribution</name> <!-- NOTE: These dependency declarations are only required to sort this project to the end of the line in the multimodule build. Since we only include the child1 module in our assembly, we only need to ensure this distribution project builds AFTER that one... --> <dependencies> <dependency> <groupId>org.test</groupId> <artifactId>child1</artifactId> <version>1.0</version> </dependency> </dependencies> <build> <plugins> <plugin> <artifactId>maven-assembly-plugin</artifactId> <executions> <execution> <id>distro-assembly</id> <phase>package</phase> <goals> <goal>single</goal> </goals> <configuration> <descriptors> <descriptor>src/assembly/bin.xml</descriptor> </descriptors> </configuration> </execution> </executions> </plugin> </plugins> </build> </project>
This POM directs the Assembly Plugin to execute the single
goal when the build reaches the package
phase, and tells it to use the bin.xml
assembly descriptor when executing.
Execute!
To build the assembly, we issue the following command:
mvn clean package
This will ensure that the output directory (normally, target
), is removed before building the assembly directory.
Note: Because of a quirk in Maven 2.0's execution model relating to aggregator goals and the inheritance hierarchy, we need to explicitly execute the package phase ahead of the assembly invocation, to ensure all modules have been built.
Examining the Output
When the Maven execution completes, the following directory structure should be left. Remember, our assembly format was dir
, which is why the output is a directory and not an archive of some sort.
Here are the directory contents:
target/distribution/distribution-1.0-bin `-- modules `-- child1 |-- child1-1.0.jar `-- junit-3.8.1.jar