Sonatype

Previous: Chapter 10

Introduction

Maven is more than a simple build tool. But this is not to say that Maven is not very good a doing simple builds. In fact that is a core feature of Maven's 95% principle (the Maven team's goals are to make available tools for 95% of the most common use-cases). With this in mind, the maven-assembly-plugin was created to handle the most common artifact packaging concerns - such as bundling source code, or zipping up an entire project. I suggest you make close friends with this plugin, since - you may find - it is capable of most packaging features you may require.

Using Assemblies

The maven-assembly-plugin contains seven goals. The most common goals are assembly - meant to be used as a stand-alone goal (since it forks a lifecycle to the package phase) - and attached - which does not fork a lifecycle, and is used to attach an assembly to a build lifecycle (defaulting to package). Those two goals have corresponding "directory" goals - directory and directory-inline, respectively) to run assemblies that assemble projects into a build directory, rather than a single zip-type archive artifact (jar, tar.gz, etc.). Finally, there are two more corresponding goals for projects under multi-module projects - single and directory-single, respectively.

The seventh goal is unpack which is rarely necessary to use - since one should write a descriptor which executes the same behavior: to unpack dependencies inside the archive.

mvn assembly:assembly
mvn assembly:directory
<project>
  ...
  <build>
    <plugins>
      <plugin>
        <artifactId>maven-assembly-plugin</artifactId>
        <executions>
          <execution>
            <id>assemble</id>
            <goals>
              <goal>attached</goal>
              <goal>directory-inline</goal>
              <goal>single</goal>
              <goal>directory-single</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
</project>

Default Assemblies

The simplest assemblies to use are the pre-defined ones. At the time of this writing, there are four types (note that the first three assemblies each create three file typed artifacts - zip, tar.gz and tar.bz2):

  • bin - Assembles artifacts packaged with README*, LICENSE*, and NOTICE* files in the project's base directory.
  • src - Assembles artifacts packaged with README*, LICENSE*, NOTICE* and the pom.xml, along with all files under the project's src directory.
  • project: this is used to create artifacts of the entire source project, including the Maven POM and other files outside of your source directory structure, but excluding all SCM metadata directories - such as CVS>> or <<<.svn - and the $basedir/target directory (specifically - if you output to a directory other than target, you may pack up binaries).
  • jar-with-dependencies - Explodes all dependencies of this project and packages the exploded forms into a jar along with the project's outputDirectory. Note that this default assembly descriptor only creates a jar, not the three zip types.

There are two ways to use the above assemblies. As usual - the command line, or under the plugin's configuration element in the target project's pom. If you use the command-line, only one assembly may be used, via the descriptorId property.

mvn assembly:assembly -DdescriptorId=jar-with-dependencies

Otherwise, you may define one or more descriptorRefs assemblies.

<project>
  ...
  <build>
    <plugins>
      <plugin>
        <artifactId>maven-assembly-plugin</artifactId>
        <configuration>
          <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
            <descriptorRef>src</descriptorRef>
          </descriptorRefs>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

When an assembly is utilized, the name of the assembly is used as the assembly artifact's classifier. This means that the name of the descriptor id is appended to the end of the artifact file's prefix. The usage of an assembly does not affect the standard artifact created by a project's packaging type. For example, if I have a project with coordinates of com.mycompany:my-app:1.0:jar and configured descriptorRef of src, then four artifacts are created: my-app-1.0.jar, and the three src assembly artifacts: my-app-1.0-src.zip, my-app-1.0-src.tar.gz, and my-app-1.0-src.tar.bz2.

Custom Assemblies

Although the default assemblies above will cover the majority of use-cases, the ability to use custom assemblies is equally important. If your group has an assembly, simple place the descriptor xml file under your project structure and link to it within the POM. You may wish to bundle the assembly execution to a phase as well.

Beyond the POM, this is the largest configuration file in the standard Maven plugin set.

<project>
  ...
  <build>
    <plugins>
      <plugin>
        <artifactId>maven-assembly-plugin</artifactId>
        <configuration>
          <descriptor>src/main/assembly/my-src.xml</descriptor>
        </configuration>
        <executions>
          <execution>
            <goals>
              <goal>attached</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>

Creating Assemblies

It is a relatively simple task to create a descriptor that specifies the type and scope of files that are to be packaged as an assembly artifact. As mentioned above, assemblies are defined in xml files and imported via the maven-assembly-plugin configuration. A simple assembly descriptor that zips up a project's source code would look like this:

<assembly>
  <id>my-src</id>
  <formats>
    <format>zip</format>
  </formats>
  <fileSets>
    <fileSet>
      <includes>
        <include>LICENSE*</include>
        <include>pom.xml</include>
      </includes>
    </fileSet>
    <fileSet>
      <directory>src</directory>
    </fileSet>
  </fileSets>
</assembly>

We will look at the different types of components available for assembly, but first look at the formats that an assembly may package as.

NOTE: To avoid duplication of descriptor elements, and as an easy way to conceptualize element sets that appear in multiple locations - look for named BEGIN: / END: comment blocks. Where the comment names appear again, those same elements appear serving the same function.

Archive types

When the package phase is run it will still create the artifact of the packaging type, for example the target/artifactId-version.jar file, but in addition will bundle up the source code into a target/artifactId-version-src.zip file. This assumbly will generate all the formats defined above. The possible archive types are limited to the Plexus implementations of the org.codehaus.plexus.archiver.Archiver component, in the plexus-archiver project. The list at the time of this writing is:

  • bzip2
  • dir
  • ear
  • gzip
  • jar
  • tar
  • tar.gz
  • tar.bz2
  • tbz2
  • war
  • zip

One or more of these formats may be defined in the descriptor.

<assembly>
  <id>release-bin</id>
  <formats>
    <format>tar.gz</format>
    <format>tbz2</format>
    <format>zip</format>
  </formats>
  <baseDirectory>release/bin</baseDirectory>
  <includeBaseDirectory>true</includeBaseDirectory>
  <includeSiteDirectory>false</includeSiteDirectory>
  ...
</assembly>

Other than the required id and formats elements, there are three more simple top-level elements.

  • baseDirectory - The name of the base directory to use if includeBaseDirectory is set to true. Defaults to the project's artifactId. Everything within the assembly-generated archive will not be in the root of the archive, but under the baseDirectory instead.
  • includeBaseDirectory - Includes the base directory in the artifact if set to true - the default - otherwise the output will be put in the archive's root.
  • includeSiteDirectory - Set to true if you wish to assemble the project's site into the artifact, otherwise false - the default.

Files

The simplest and most common assemblies package collections of denoted project files into an artifact. It does this in two ways, by specifying single files, or sets of files (directories).

Single files are moved into the assembly in a very straightforward manner, and can probably be understood by the example below, without much description.

<assembly>
  ...
  <files>
    <file>
      <source>src/main/exec/linux-run.sh</source>
      <outputDirectory>bin</outputDirectory>
      <destName>run.sh</destName>
      <filtered>true</filtered>
      <lineEnding>unix</lineEnding>
      <fileMode>0554</fileMode>
    </file>
  </files>
  ...
</assembly>
  • source - The module's relative path - or absolute path - to the file to include in the assembly.
  • outputDirectory - The directory within the assembly to output the file to.
  • destName - The destination filename in the outputDirectory - if not set, the default is source filename.
  • filtered - true or false, depending upon whether the file should be filtered by Maven (if you recall, filtering in Maven replaces a text file's ${property.name} with the value of property.name - where this is a POM property).
  • lineEnding - The style of the archived file's line-endings; there are five legal values.
    • keep - Keep all line endings as they are - default
    • crlf - Carraige-return/line-feed
    • lf - Line-feed
    • unix - Unix-style line endings
    • dos - DOS-style line endings
  • fileMode - The archived file's mode encoded in Unix's octal permission style - (user)(group)(other) where each component is a sum of read = 4, write = 2, or execute = 1. Defaults to 0644. From the value 0554 above: the user and group can read/execute, while other can read only.
<assembly>
  ...
  <!-- BEGIN: File Sets -->
  <fileSets>
    <fileSet>
      <directory>src/main/java</directory>
      <filtered>false</filtered>
      <lineEnding>keep</lineEnding>

      <!-- BEGIN: File Set Includes/Excludes -->
      <includes>
        <include>**/*.java</include>
      </includes>
      <excludes>
        <exclude>**/*Test.java</exclude>
      </excludes>
      <!-- END: File Set Includes/Excludes -->

      <!-- BEGIN: Directory Output Mask Elements -->
      <outputDirectory>src</outputDirectory>
      <useStrictFiltering>false</useStrictFiltering>
      <useDefaultExcludes>true</useDefaultExcludes>
      <fileMode>0444</fileMode>
      <directoryMode>0755</directoryMode>
      <!-- END: Directory Output Mask Elements -->

    </fileSet>
  </fileSets>
  <!-- END: File Sets -->
  ...
</assembly>
  • directory - The absolute or relative location from the module's directory. For example, "src/main/java" would select this subdirectory of the project in which this dependency is defined.
  • filtered, lineEnding - Same as above, but for all files in the fileSet

File Set Includes/Excludes

  • includes - Contains a list of include elements which are an ant-like filename mask, denoting files to include in this fileSet. Default is **/** (all files).
  • excludes - Contains a list of exclude elements which are an ant-like filename mask, denoting files to exclude from this fileSet. Default is no exclusions. Note that excludes always take priority over includes - this is true for all include/exclude pairs.

Directory Output Mask Elements

The remainder of the fileSet description contains a set of elements used to determine several things about the output directory, including naming, file filters and final file and directory states.

  • outputDirectory - Sets the output directory relative to the root of the root directory of the assembly. For example, "log" will put the specified files in the log directory.
  • useStrictFiltering - Any include/exclude patterns which are unused in filtering any files will cause the build to fail with an error. For the example above, if the project contains no .java files, this assembly will fail.
  • useDefaultExcludes - Denotes whether the maven-assembly-plugin's standard exclusion set should apply. Defaults to true; set to false if you wish this assembly to package CVS and .svn metadata directories.
  • fileMode - Same as above, but for all files in the fileSet
  • directoryMode - Same as above, but for the directory of this fileSet. Defaults to 0755.

Dependencies

Beyond files, project dependencies are also common to package within an archive. These can be defines under the dependencySets element list. The "Directory Output Mask Elements" comment is a marker for the same set of elements defined above.

<assembly>
  ...
  <!-- BEGIN: Dependency Sets -->
  <dependencySets>
    <dependencySet>
      <scope>compile</scope>

      <!-- BEGIN: Artifact Matching Includes/Excludes -->
      <includes>
        <include>com.mycompany:module*</include>
      </includes>
      <excludes>
        <exclude>com.mycompany:module3</exclude>
      </excludes>
      <!-- END: Artifact Matching Includes/Excludes -->

      <!-- BEGIN: File Output and Unpacking -->
      <outputFileNameMapping>${artifactId}</outputFileNameMapping>
      <unpack>true</unpack>
      <unpackOptions>
        <!-- File Set Includes/Excludes -->
        <filtered>true</filtered>
      </unpackOptions>
      <!-- END: File Output and Unpacking -->

      <!-- Directory Output Mask Elements -->

    </dependencySet>
  </dependencySets>
  <!-- END: Dependency Sets -->
  ...
</assembly>
  • scope - The scope for this dependency set; the are five legal values are the same as the POM's dependency scopes.
    • runtime - this scope indicates that the dependency is not required for compilation, but is for execution. It is in the runtime and test classpaths, but not the compile classpath. This is the default.
    • compile - this is the default scope, used if none is specified. Compile dependencies are available in all classpaths.
    • test - this scope indicates that the dependency is not required for normal use of the application, and is only available for the test compilation and execution phases.
    • provided - this is much like compile, but indicates you expect the JDK or a container to provide it. It is only available on the compilation classpath, and is not transitive.
    • system - this scope is similar to provided except that you have to provide the JAR which contains it explicitly. The artifact is always available and is not looked up in a repository.

Artifact Matching Includes/Excludes

  • includes - Contains a list of include elements, each containing an artifact-matching pattern - modules matching these elements will be included in this set. If none is present, then includes represents all valid values.
  • excludes - Similar to includes, but modules matching these elements will be excluded from the set. excludes takes priority over includes

File Output and Unpacking

  • outputFileNameMapping - The pattern for all dependencies included in the assembly. Default is ${artifactId}-${version}.${extension} where the properties are the dependency values.
  • unpack - Unpack all dependencies into the specified output directory if true, else dependencies will be includes as archives (such as jars), which is the default.
  • unpackOptions - Allows the specification of includes, excludes and filtering options for unpacked items from dependency artifacts.
    • includes, excludes, filtered - Same descriptions as fileSet definitions above

A little more information about the artifact-matching patterns - from the assembly-plugin document:

The following easy rules should be applied when specifying artifact-matching patterns:

  1. Artifacts are matched by a set of identifier strings. In the following strings, type is 'jar' by default, and classifier is omitted if null.
    • groupId:artifactId
    • groupId:artifactId:type:classifier
    • groupId:artifactId:version:type:classifier
  2. Any '*' character in an include/exclude pattern will result in the pattern being split, and the sub-patterns being matched within the three artifact identifiers mentioned above, using String.indexOf(..).
  3. When no '*' is present in an include/exclude pattern, the pattern will only match if the entire pattern equals one of the three artifact identifiers above, using the String.equals(..) method.
  4. In case you missed it above, artifact-identification fields are separated by colons (':') in the matching strings. So, a wildcard pattern that matches any artifact of type 'war' might be specified as *:war:*.

Modules

A moduleSet represent one or more modules present inside a pom.xml. This allows you to include sources or binaries belonging to a multi-module project's individual modules. It contains the ability to extract specific modules, sources, and even binaries

<assembly>
  ...
  <moduleSets>
    <moduleSet>
      <includeSubModules>true</includeSubModules>

      <!-- Artifact Matching Includes/Excludes -->

      ...
    <moduleSet>
  <moduleSets>
  ...
</assembly>
  • includeSubModules - Process all sub-modules under this module-set if true - the default; else the sub-modules will be excluded from processing.
  • includes, excludes - Same descriptions as dependencySet definitions above

The sources element represents non-output files from specified module projects. The element specifies a set of files (fileSets) and contains the "Directory Output Mask Elements" to specify how these files will be output into the assembly archive. Moreover, sources contains three other elements.

<assembly>
  ...
  <moduleSets>
    <moduleSet>
      ...
      <sources>
        <includeModuleDirectory>true</includeModuleDirectory>
        <outputDirectoryMapping>${artifactId}</outputDirectoryMapping>
        <excludeSubModuleDirectories></excludeSubModuleDirectories>

        <!-- File Sets -->

        <!-- File Set Includes/Excludes -->

        <!-- Directory Output Mask Elements -->

      </sources>
      ...
    </moduleSet>
  </moduleSets>
  ...
</assembly>
  • includeModuleDirectory - The outputDirectoryMapping value is prepended to the outputDirectory values of any fileSets applied to it if true - the default.
  • outputDirectoryMapping - The base directory pattern for all modules included in this assembly. Default is the module's ${finalName}.
  • excludeSubModuleDirectories - Specifies whether sub-module directories below the current module should be excluded from fileSets applied to that module. This might be useful if you only mean to copy the sources for the exact module list matched by this ModuleSet, ignoring (or processing separately) the modules which exist in directories below the current one. Default value is true.

The binaries element represents the output files of matching module projects. This element specifies a set of dependencies (dependencySets), the set of "File Output" elements, and also contains the "Directory Output Mask Elements" to specify how these files will be output into the assembly archive. Moreover, sources contains two other elements.

<assembly>
  ...
  <moduleSets>
    <moduleSet>
      ...
      <binaries>
        <attachmentClassifier></attachmentClassifier>
        <includeDependencies>true</includeDependencies>

        <!-- Dependency Sets -->

        <!-- File Output and Unpacking -->

        <!-- File Set Includes/Excludes -->

        <!-- Directory Output Mask Elements -->

      </binaries>
    </moduleSet>
  </moduleSets>
  ...
</assembly>
  • attachmentClassifier -
  • includeDependencies - Include the direct and transitive dependencies of the project modules if true - the default; else, only include the module packages.

Assembling Maven Repositories

<assembly>
  ...
  <repositories>
    <repository>
      <includeMetadata>true</includeMetadata>
      <scope>runtime</scope>
      <groupVersionAlignments>
        <groupVersionAlignment>
          <id>com.mycompany</id>
          <version>2.1</version>
          <excludes>
            <exclude>my-artifact1</exclude>
          </excludes>
        </groupVersionAlignment>
      </groupVersionAlignments>

      <!-- File Set Includes/Excludes -->

      <!-- Directory Output Mask Elements -->

    </repository>
  </repositories>
  ...
</assembly>
  • includeMetadata - If set to true, this property will trigger the creation of repository metadata which will allow the repository to be used as a functional remote repository. Default value is false.
  • scope - Specifies the scope for artifacts included in this repository. Default scope value is "runtime".
  • groupVersionAlignments - Align a group of artifacts to a specified version. For example, all artifacts with groupId of "com.mycompany" can be aligned to one version "2.1", excluding specific artifacts if desired.
    • id - The groupId of the artifacts for which you want to align the versions.
    • version - The version you want to align this group to.
    • excludes - When exclude subelements are present, they define the artifactIds of the artifacts to exclude. If none is present, then excludes represents no exclusions. An exclude is specified by providing one or more of exclude subelements.

Assembly Tricks and Tips

The first half of this chapter went over basic useage and a look at the assembly descriptor - what the elements are and logical groupings. Much of that information can be gathered from the standard documentation but was added here for completeness (online references are linked at the end of this chapter). The rest of this section will describe some tricks/tips to make the most out of your maven-assembly-plugin experience.

Externalizing Component Descriptors

There is one last element in the assembly descriptor that we have skipped - componentDescriptors. This allows one to reuse common component descriptions across several assemblies. A component element is placed in a seperate file and contains only four elements from the assembly descriptor: fileSets, files, dependencySets, repositories.

For example: suppose we have a project with two assemblies - one for assembling all xml files in a project, and another for assembling all xml files in a project and it's dependencies. The components "all xml files in a project" overlap in the two assemblies - so we externalize them into a file named src/main/assembly/component/xml-files.xml.

<component>
  <fileSets>
    <fileSet>
      <directory>src</directory>
      <outputDirectory>xml</outputDirectory>
      <includes>
        <include>**/*.xml</include>
      </includes>
    </fileSet>
  </fileSets>
</component>

This component descriptor can then be imported as a path from the project's ${basedir}, creating the two assemblies below.

<assembly>
  <id>local-xml</id>
  <componentDescriptors>
    <componentDescriptor>src/main/assembly/component/xml-files.xml</componentDescriptor>
  </componentDescriptors>
</assembly>
<assembly>
  <id>all-xml</id>
  <dependencySets>
    <dependencySet>
      <scope>compile</scope>
      <unpack>true</unpack>
      <unpackOptions>
        <includes>
          <include>**/*.xml</include>
        </includes>
        <filtered>true</filtered>
      </unpackOptions>
      <outputDirectory>xml</outputDirectory>
      <useStrictFiltering>true</useStrictFiltering>
    </dependencySet>
  </dependencySets>
  <componentDescriptors>
    <componentDescriptor>src/main/assembly/component/xml-files.xml</componentDescriptor>
  </componentDescriptors>
</assembly>

Example Module Assembly

Modules sets are complex beasts to wrestle, as you might imagine from the descriptor above. The maven-assembly-plugin has some excellent documentation concerning the moduleSet element and it's usage. For the sake of completeness, we'll cover a quick example here.

Suppose you have a multi-module project named com.mycompany:my-app, with two modules com.mycompany:module1 and com.mycompany:module2. The directory structure is as follows:

my-app
|-- module1
|   `-- ... some projecty stuff in here ...
|-- module2
|       `-- runscript
|               `-- run.sh
|-- pom.xml
`-- src
        `-- main
                `-- assembly
                    `-- bin-release.xml

We want to create a binary release bundle, that builds the module1, and then zip the jar up in a lib directory, with a script that runs the module1 jar in a bin directory that lives in module2. Finally, when a user unzips the bundle it will extract to a directory of the project name - my-app.

<project>
  <groupId>com.mycompany</groupId>
  <artifactId>my-app</artifactId>
  <version>1.0</version>
  <packaging>pom</packaging>
  <modules>
    <module>module1</module>
    <module>module2</module>
  </modules>

  <build>
    <plugins>
      <plugin>
        <artifactId>maven-assembly-plugin</artifactId>
        <configuration>
          <descriptorSourceDirectory>src/main/assembly</descriptorSourceDirectory>
        </configuration>
        <executions>
          <execution>
            <id>bin-release</id>
            <phase>package</phase>
            <goals>
              <goal>attached</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
</project>

The bin-release.xml descriptor then includes the scripts of module2, while packaging the binaries of all other modules (and submodules) and their dependencies into a lib directory. These files are then placed into a

<assembly>
  <id>bin-release</id>
  <formats>
    <format>zip</format>
  </formats>
  <includeBaseDirectory>true</includeBaseDirectory>
  <baseDirectory>${artifactId}</baseDirectory>
  <moduleSets>
    <moduleSet>
      <excludes>
        <exclude>com.mycompany:module2</exclude>
      </excludes>
      <includeSubModules>true</includeSubModules>
      <binaries>
        <outputDirectory>lib</outputDirectory>
        <unpack>false</unpack>
        <includeDependencies>true</includeDependencies>
        <dependencySets>
          <dependencySet>
            <scope>runtime</scope>
            <outputDirectory>lib</outputDirectory>
          </dependencySet>
        </dependencySets>
      </binaries>
    </moduleSet>

    <moduleSet>
      <includes>
        <include>com.mycompany:module2</include>
      </includes>
      <sources>
        <fileSets>
          <fileSet>
            <directory>src/main/runscript</directory>
            <filtered>true</filtered>
            <useStrictFiltering>true</useStrictFiltering>
            <outputDirectory>bin</outputDirectory>
            <includes>
              <include>*.sh</include>
            </includes>
            <fileMode>0544</fileMode>
          </fileSet>
        </fileSets>
      </sources>
    </moduleSet>
  </moduleSets>
</assembly>

All one need now do to execute bin-release is run the package phase for the my-app project (in it's ${basedir}).

mvn package

Does that seem like a lot of configuration? Try writing your own plugin... or doing it in Ant! :)

OS-specific distributions with Profiles

Similar to the previous task, a common usage for assemblies is to generate multiple distributions with little work. Combined with POM profiles, assemblies are suddenly composed by a new dimension.

<project>
  <build>
    <plugins>
      <plugin>
        <artifactId>maven-assembly-plugin</artifactId>
        <configuration>
          <descriptor>src/main/assembly/${assembly.osname}</descriptor>
        </configuration>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>attached</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>

  <profiles>
    <profile>
      <id>linux</id>
      <activation>
        <os>
          <family>linux</family>
        </os>
      </activation>
      <properties>
        <assembly.osname>linux-assembly.xml</assembly.osname>
      </properties>
    </profile>
    <profile>
      <id>windows</id>
      <activation>
        <os>
          <family>windows</family>
        </os>
      </activation>
      <properties>
        <assembly.osname>windows-assembly.xml</assembly.osname>
      </properties>
    </profile>
  </profiles>
</project>

Creating Test Jars

Although not usually condoned (we prefer you use the jar:test-jar goal), it is possible to use maven-assembly-plugin to package a project's test code usable by other projects.

<assembly>
  <id>test-jar</id>
  <formats>
    <format>jar</format>
  </formats>
  <includeBaseDirectory>false</includeBaseDirectory>
  <fileSets>
    <fileSet>
      <directory>${testOutputDirectory}</directory>
    </fileSet>
  </fileSets>
</assembly>

The plus-side of using assembly for creating test-jars is the increased level of control. The downside is that test-jar is a legitimate dependency type, whereas creating test-jars via assembly would instead be classifiers. In short, use jar:test-jar, until you have a good reason not to.

Removing SCM Metadata

It is sometimes necessary to remove content management metadata throughout a project - for example remove all .svn directories. This is not really a condoned usage of the assembly plugin, but a useful one-line hack:

mvn assembly:directory -DdescriptorId=project

This will copy all project files sans SCM metadata to a target directory.

Descriptors

Summary

Assemblies are useful when the standard packaging constructs cannot serve your purposes. Moreover, they have a level of control over packaging external items that more specific plugins such as maven-source-plugin and maven maven-dependencies-plugin may not. Finally, assemblies can be most often useful for packaging a finished project into several different packaging formats at once for serving a wide-range of users who may prefer bz2 to zip.


Previous: Chapter 10