はい、承知いたしました。Maven Assembly Pluginについて、基本的な概念から詳細な設定方法、具体的な使い方、そしてよくあるユースケースまで、約5000語で解説する記事を作成します。
Maven Assembly Pluginとは?基本と使い方を徹底解説
はじめに:なぜMaven Assembly Pluginが必要なのか?
MavenはJavaプロジェクトのビルド、依存関係管理、テスト、デプロイを自動化するための強力なツールです。mvn packageコマンドを実行すると、通常、プロジェクトのタイプに応じた標準的なアーティファクト(例:JAR、WAR、EAR)が作成されます。しかし、多くの実際のアプリケーションやライブラリでは、単一のJARファイルだけでは不十分な場合があります。
例えば、以下のような状況を想像してみてください。
- アプリケーションの配布: アプリケーションを実行するには、メインのJARファイルの他に、依存ライブラリ群、設定ファイル、起動スクリプト、READMEファイルなどをまとめて配布する必要があります。これらを一つのZIPやtar.gzファイルにまとめたい。
- 依存関係を含んだ実行可能JAR (Uber JAR/Fat JAR): すべての依存ライブラリをメインのJARファイル内に含めて、
java -jarコマンドだけで実行できるようにしたい。 - ソースコードやJavadocの配布: プロジェクトのソースコードや生成されたJavadocをまとめて、開発者やユーザーに提供したい。
- 特定のファイル群のバンドル: プロジェクト内の特定のリソースファイルやスクリプトだけを抽出して、別の用途で利用できる形式でまとめたい。
これらのニーズに対して、Mavenの標準的なパッケージング機能だけでは柔軟に対応できません。そこで登場するのが Maven Assembly Plugin です。
Maven Assembly Pluginは、プロジェクトの成果物、依存関係、モジュール、サイトコンテンツ、ファイル群などを組み合わせ、様々な形式(ZIP、TAR、TAR.GZ、TAR.BZ2、DIR、JARなど)でパッケージングすることを可能にするプラグインです。これにより、アプリケーション配布パッケージ、カスタムライブラリバンドル、ソースコードバンドルなど、標準以外の複雑なアーティファクトを簡単に作成できます。
この記事では、Maven Assembly Pluginの基本的な概念、設定方法、主要な要素、具体的な使い方、そして高度なトピックまでを、詳細なコード例と共に解説します。
1. Maven Assembly Pluginの基本概念
Maven Assembly Pluginの核となる概念は以下の2つです。
- Assembly (アセンブリ): 最終的に作成されるパッケージ(ZIPやtar.gzなど)そのものを指します。これは、プロジェクトの成果物、依存関係、特定のファイル群などが組み合わされたものです。
- Descriptor (ディスクリプタ): Assemblyの構成方法(何を含めるか、どの形式で出力するか、ファイルの配置場所、ファイルモードなど)を定義するXMLファイルです。Assembly PluginはこのDescriptorを読み込んでAssemblyを作成します。
Assembly Pluginを使用する基本的な流れは以下のようになります。
- プロジェクトの
pom.xmlに Maven Assembly Plugin を追加する。 - Assemblyの構成を定義するDescriptorファイル(通常は
src/main/assemblyまたはsrc/main/assembliesディレクトリに配置)を作成する。 pom.xmlのプラグイン設定で、作成したDescriptorファイルを指定する。- Mavenのビルドコマンド(例:
mvn package)を実行し、Assemblyを作成する。
Pluginは指定されたDescriptorに従って、プロジェクトのビルドディレクトリ(通常 target ディレクトリ)内に定義されたAssemblyを作成します。
2. Pluginの追加と基本設定
まず、Maven Assembly Pluginをプロジェクトに追加する必要があります。これは pom.xml の <build> セクション内にある <plugins> セクションで行います。
xml
<project>
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.6.0</version> <!-- 利用可能な最新バージョンを指定 -->
<executions>
<execution>
<id>make-assembly</id> <!-- 実行IDは任意 -->
<phase>package</phase> <!-- packageフェーズで実行 -->
<goals>
<goal>single</goal> <!-- singleゴールで一つのAssemblyを作成 -->
</goals>
<configuration>
<!-- ここでDescriptorファイルを指定 -->
<!-- 例: デフォルトのDescriptorRefを使用する場合 -->
<!-- <descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs> -->
<!-- 例: カスタムDescriptorを使用する場合 -->
<descriptors>
<descriptor>src/main/assembly/mydistribution.xml</descriptor>
</descriptors>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
...
</project>
設定要素の解説:
<groupId>,<artifactId>,<version>: プラグインの座標。公式サイトで最新バージョンを確認して指定してください。<executions>: プラグインの実行設定を定義します。複数の実行設定を持つことができます。<execution>: 個々の実行設定。<id>: この実行設定の一意なID。<phase>: この実行設定をどのビルドフェーズで実行するか指定します。通常はpackageフェーズが使われます。packageフェーズでは、プロジェクトの主要な成果物(JAR, WARなど)が既に作成された後にAssemblyが生成されます。<goals>: この実行で実行するプラグインのゴールを指定します。Assembly Pluginで最もよく使われるゴールはsingleです。single: 一つまたは複数のDescriptorファイルからAssemblyを作成します。これが最も一般的な使い方です。assembly:singleと似ていますが、後方互換性のために存在します。通常はsingleを使用します。help: プラグインのヘルプ情報を表示します。
<configuration>: この実行設定に関する様々な設定を行います。<descriptorRefs>: Assembly Pluginに組み込み済みの標準Descriptorを使用する場合に指定します。例えば、jar-with-dependenciesは依存関係をすべて含んだJARを作成するための組み込みDescriptorです。<descriptors>: ユーザーが定義したカスタムDescriptorファイルへのパスを指定します。<descriptor>要素の中にファイルパスを記述します。複数のDescriptorを指定することも可能です。
Descriptorファイルの配置場所:
カスタムDescriptorファイルは、プロジェクトの標準的なソースディレクトリ配下に配置するのが一般的です。推奨される場所は src/main/assembly/ または src/main/assemblies/ ディレクトリです。ここにXMLファイル(例: mydistribution.xml)として配置します。
3. Assembly Descriptorの構造と主要要素
Descriptorファイル(例: src/main/assembly/mydistribution.xml)は、Assemblyの構成を詳細に定義するXMLファイルです。そのルート要素は <assembly> です。
基本的なDescriptorファイルの構造は以下のようになります。
“`xml
“`
各主要要素について詳しく見ていきましょう。
3.1. <id> 要素
<id> 要素は、Assemblyの識別子を指定します。このIDは、作成されるアーカイブファイル名の一部として使用されます。
例: <id>distribution</id>
作成されるファイル名: artifactId-version-distribution.zip, artifactId-version-distribution.tar.gz など。
このIDは必須です。特に <descriptorRefs> を使用せず、<descriptors> でカスタムDescriptorを指定する場合は必ず定義してください。
3.2. <formats> 要素
<formats> 要素は、作成したいAssemblyの出力形式を一つまたは複数指定します。
利用可能な主な形式:
zip: ZIPアーカイブ (.zip)tar: TARアーカイブ (.tar)tar.gz: GZ圧縮されたTARアーカイブ (.tar.gz)tar.bz2: BZ2圧縮されたTARアーカイブ (.tar.bz2)tar.snappy: Snappy圧縮されたTARアーカイブ (.tar.snappy)tar.xz: XZ圧縮されたTARアーカイブ (.tar.xz)dir: ディレクトリとして出力(圧縮はされない)jar: JARファイル (.jar) – 通常、<includeBaseDirectory>はfalseに設定され、依存関係を含めるためによく使われます。
例:
xml
<formats>
<format>zip</format>
<format>tar.gz</format>
<format>dir</format>
</formats>
これにより、同じ内容で3つの形式のAssemblyが作成されます。
3.3. <includeBaseDirectory> 要素
<includeBaseDirectory> 要素は、作成されるAssemblyのルートに、プロジェクト名とバージョンを含むトップレベルディレクトリを含めるかどうかを指定します。デフォルト値は true です。
例: <includeBaseDirectory>true</includeBaseDirectory>
作成されるアーカイブを開くと、例えば myproject-1.0/ というディレクトリがあり、その中にAssemblyの内容が配置されます。
例: <includeBaseDirectory>false</includeBaseDirectory>
作成されるアーカイブを開くと、Assemblyの内容が直接ルートに配置されます。
多くの配布パッケージでは、解凍した際に内容が散らばらないように true に設定するのが一般的です。ただし、Executable JAR (jar形式) のように単一のファイルを意図する場合は false に設定することが多いです。
3.4. <fileSets> 要素
<fileSets> 要素は、プロジェクトのディレクトリ構造内のファイル群をAssemblyに含めるために使用します。特定のディレクトリにあるファイル群を、Assembly内の指定したパスにコピーしたい場合に利用します。
<fileSet> 要素は以下のサブ要素を持ちます。
<directory>: コピー元のルートディレクトリを指定します。通常はプロジェクトのベースディレクトリからの相対パスを指定します(例:${project.basedir}/src/main/resources)。パスはMavenのプロパティ(${project.basedir}や${project.build.directory}など)を使用できます。<outputDirectory>: コピー先 Assembly内のパスを指定します。Assemblyのルートからの相対パスです。<includes>: 含めたいファイルのパターンを指定します。Antのファイルセットパターンを使用できます(例:**/*.properties,scripts/*.sh)。<excludes>: 除外したいファイルのパターンを指定します。<filtered>: このファイルセット内のファイルをMavenのリソースフィルタリングと同様にフィルタリングするか指定します (trueまたはfalse)。プロパティ置換(例:${project.version})を行いたい場合にtrueにします。<permissions>: このファイルセット内のファイルやディレクトリのパーミッション(ファイルモード)を指定します。<fileMode>: ファイルに適用するパーミッションを8進数で指定します(例:0644)。<directoryMode>: ディレクトリに適用するパーミッションを8進数で指定します(例:0755)。
例: 設定ファイルと起動スクリプトを含める
プロジェクト構造:
myproject/
├── pom.xml
└── src/main/
├── resources/
│ └── config.properties
└── scripts/
└── startup.sh
Descriptor (mydistribution.xml):
“`xml
<!-- スクリプト群を Assembly ルートの bin ディレクトリにコピー -->
<fileSet>
<directory>${project.basedir}/src/main/scripts</directory>
<outputDirectory>bin</outputDirectory>
<includes>
<include>*.sh</include>
</includes>
<fileMode>0755</fileMode> <!-- 実行可能パーミッションを設定 -->
</fileSet>
…
“`
これにより、Assembly内に myproject-1.0/config/config.properties および myproject-1.0/bin/startup.sh が含まれます。
3.5. <dependencySets> 要素
<dependencySets> 要素は、プロジェクトの依存関係(Mavenの依存関係として定義されているJARなど)をAssemblyに含めるために使用します。アプリケーションの実行に必要なライブラリ群をまとめる際に非常に便利です。
<dependencySet> 要素は以下のサブ要素を持ちます。
<outputDirectory>: コピー先 Assembly内のパスを指定します。通常はlibやlibsといった名前のディレクトリを指定します。<useProjectArtifact>: プロジェクト自身の成果物(通常mvn packageで生成されるJARなど)を含めるかどうかを指定します (trueまたはfalse)。デフォルトはtrueです。Executable JARを作成する場合はtrueにしますが、配布パッケージでメインJARと依存ライブラリを分けたい場合は、メインJARは別の<fileSet>で含めるか、この設定をfalseにし、<fileSet>で明示的に含める方法もあります。<unpack>: 依存関係のJARファイルを解凍して中身をAssemblyに含めるかどうかを指定します (trueまたはfalse)。Executable JARを作成する際に、依存関係のクラスファイルをメインJARにまとめたい場合(jar形式 +<unpack>true)に使われることがありますが、これはMaven Shade Pluginの方が適していることが多いです。通常はfalseにして、依存JARをそのまま含めます。<scope>: 含める依存関係のスコープを指定します(例:runtime,compile,test,provided)。通常、アプリケーションの実行に必要なのはruntimeスコープの依存関係です。<includes>: 含めたい依存関係を{groupId}:{artifactId}:{type}:{classifier}または{groupId}:{artifactId}のパターンで指定します。<excludes>: 除外したい依存関係をパターンで指定します。
例: 実行時依存ライブラリを lib ディレクトリに含める
Descriptor (mydistribution.xml):
“`xml
…
“`
これにより、Assembly内に myproject-1.0/myproject-1.0.jar および myproject-1.0/lib/*.jar (runtimeスコープの依存関係)が含まれます。
3.6. <files> 要素
<files> 要素は、特定の個別のファイルをAssemblyに含めるために使用します。<fileSets> はディレクトリ単位でパターンマッチングを行いますが、<files> はファイル単位で細かく指定する場合に使用します。
<file> 要素は以下のサブ要素を持ちます。
<source>: コピー元のファイルパスを指定します。<outputDirectory>: コピー先 Assembly内のディレクトリパスを指定します。<destName>: コピー先 Assembly内でのファイル名を指定します。指定しない場合は元のファイル名が使用されます。<filtered>: このファイルをフィルタリングするか指定します。<permissions>: このファイルに適用するパーミッションを指定します。
例: READMEファイルを含める
Descriptor (mydistribution.xml):
xml
<assembly ...>
<id>distribution</id>
<formats>
<format>zip</format>
</formats>
<includeBaseDirectory>true</includeBaseDirectory>
<files>
<!-- プロジェクトルートの README.md を Assembly ルートにコピー -->
<file>
<source>${project.basedir}/README.md</source>
<outputDirectory>/</outputDirectory> <!-- Assembly ルート -->
<destName>README.txt</destName> <!-- ファイル名を変更してコピー -->
<filtered>false</filtered>
<fileMode>0644</fileMode>
</file>
</files>
...
</assembly>
3.7. <moduleSets> 要素 (マルチモジュールプロジェクト)
<moduleSets> 要素は、マルチモジュールプロジェクトにおいて、子モジュールの成果物や依存関係をAssemblyに含めるために使用します。
<moduleSet> 要素内で、含める子モジュールを指定し、その成果物 (<binaries>) やソース/Javadoc (<sources>) をどのように含めるかを定義します。
例: 子モジュールのJARと依存関係を含める
親プロジェクトのDescriptor (parent-assembly.xml):
“`xml
“`
<moduleSet> の <binaries> 設定内で <outputDirectory> に ${module.artifactId} のようなプロパティを使用することで、各モジュールの成果物をモジュールごとのサブディレクトリに配置できます。
3.8. <repositorySets> 要素 (あまり一般的ではない)
<repositorySets> 要素は、MavenリポジトリからAssemblyにアーティファクトを含めるために使用します。これは、プロジェクトの依存関係として定義されていないアーティファクトや、リモートリポジトリから直接何かを取得したい場合に理論上は使用できますが、通常はプロジェクトの依存関係として管理する方が一般的で、<dependencySets> を使用します。
3.9. <componentDescriptors> 要素 (高度な使い方)
<componentDescriptors> 要素は、Assembly Descriptorの一部を別のXMLファイル(通常は component.xml という名前)として定義し、それを参照するために使用します。これにより、Assembly Descriptorを複数の部分に分割したり、異なるAssembly Descriptor間で共通の設定を再利用したりできます。
例えば、共通のファイルセットや依存関係セットの定義を my-common-component.xml として分離し、複数のAssembly Descriptorからそれを参照する、といった使い方が可能です。
4. 組み込み済みDescriptor (descriptorRefs)
Maven Assembly Pluginには、よく使われるAssemblyパターンに対応するための組み込み済みDescriptorがいくつか用意されています。これらを使用する場合、<configuration> 内で <descriptorRefs> 要素を使って参照するIDを指定します。カスタムDescriptorファイル (<descriptors>) を作成する必要はありません。
主な組み込み済みDescriptor:
bin: 実行可能バイナリ配布形式。通常、実行スクリプト、JARファイル、依存ライブラリをまとめて含むディレクトリ構造を作成し、tar.gzまたはzip形式で圧縮します。src: ソースコード配布形式。プロジェクトのソースコードとPOMファイルをまとめたアーカイブを作成します。jar-with-dependencies: プロジェクトの成果物(JAR)とすべての依存関係(通常runtimeスコープ)を単一のJARファイルに含めます。これはUber JAR/Fat JARを作成する最も簡単な方法の一つですが、Maven Shade Pluginの方がより高度な機能(クラスのリロケーションなど)を提供するため、そちらが推奨される場合が多いです。assembly-with-dependencies: プロジェクトの成果物とすべての依存関係をディレクトリまたはアーカイブにまとめる形式。binと似ていますが、より一般的な用途向けです。java-client: Javaクライアントライブラリの配布形式。JARファイル、依存ライブラリ、ソース、Javadocなどを含む場合があります。
例: 組み込み済み jar-with-dependencies Descriptorを使用する
xml
<project>
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.6.0</version>
<executions>
<execution>
<id>make-fat-jar</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<!-- 作成されるJARファイル名に付けるsuffixを変更したい場合 -->
<!-- <appendAssemblyId>true</appendAssemblyId> -->
<!-- appendAssemblyId が true の場合、ファイル名は artifactId-version-assemblyId.jar となる -->
<!-- false の場合、ファイル名は artifactId-version.jar となる (デフォルトは true) -->
<!-- <finalName>${project.artifactId}-${project.version}-with-deps</finalName> --> <!-- 別名で出力したい場合 -->
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
...
</project>
この設定で mvn package を実行すると、target/your-artifact-version-jar-with-dependencies.jar というファイルが作成されます。このJARファイルには、プロジェクト自身のクラスファイルと、依存関係のすべてのクラスファイルが含まれています。ただし、同じ名前のクラスファイルが依存関係間で衝突した場合(Class Name Collision)、どちらか一方が優先されるため注意が必要です。Maven Shade Pluginは、このような衝突を回避するためのリロケーション機能などを提供しています。
5. 具体的な使い方とユースケース別のDescriptor例
ここでは、実際のユースケースに合わせたDescriptorファイルの具体的な例をいくつか紹介します。
ユースケース 1: アプリケーション配布パッケージの作成
アプリケーションの実行に必要なJAR、依存ライブラリ、起動スクリプト、設定ファイル、READMEなどをまとめて配布したい場合。
ファイル構造例:
my-app/
├── pom.xml
├── src/main/java/...
├── src/main/resources/
│ └── config.properties
├── src/main/scripts/
│ └── startup.sh
├── README.md
└── src/main/assembly/
└── distribution.xml
src/main/assembly/distribution.xml の例:
“`xml
<!-- スクリプトを bin ディレクトリにコピー -->
<fileSet>
<directory>${project.basedir}/src/main/scripts</directory>
<outputDirectory>bin</outputDirectory>
<includes>
<include>*.sh</include>
<include>*.cmd</include>
</includes>
<fileMode>0755</fileMode> <!-- Unix系実行可能 -->
<directoryMode>0755</directoryMode>
</fileSet>
<!-- 設定ファイルを config ディレクトリにコピー -->
<fileSet>
<directory>${project.basedir}/src/main/resources</directory>
<outputDirectory>config</outputDirectory>
<includes>
<include>*.properties</include>
<include>*.xml</include>
</includes>
<filtered>true</filtered> <!-- 例: config ファイル内のプロパティ置換を有効に -->
</fileSet>
<!-- メインのアプリケーション JAR をルートにコピー -->
<fileSet>
<directory>${project.build.directory}</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>${project.artifactId}-${project.version}.${project.packaging}</include>
</includes>
</fileSet>
“`
このDescriptorを使用すると、target/my-app-1.0-distribution.zip および target/my-app-1.0-distribution.tar.gz が生成されます。これらを解凍すると、以下のようなディレクトリ構造が得られます。
my-app-1.0/
├── README.md
├── my-app-1.0.jar
├── bin/
│ └── startup.sh
├── config/
│ └── config.properties
└── lib/
├── dependency1.jar
├── dependency2.jar
└── ...
pom.xml のプラグイン設定で <descriptors> に src/main/assembly/distribution.xml を指定することを忘れないでください。
ユースケース 2: ソースコード配布パッケージの作成
プロジェクトのソースコードをまとめて配布したい場合。組み込み済みの src Descriptorを使用するか、独自のDescriptorを作成します。独自のDescriptorを作成する方が、含めるファイルやディレクトリを細かく制御できます。
src/main/assembly/source.xml の例:
“`xml
<!-- main のソースコード -->
<fileSet>
<directory>${project.basedir}/src/main</directory>
<outputDirectory>src/main</outputDirectory>
</fileSet>
<!-- test のソースコード (必要であれば) -->
<fileSet>
<directory>${project.basedir}/src/test</directory>
<outputDirectory>src/test</outputDirectory>
</fileSet>
<!-- その他の標準ディレクトリ (必要であれば) -->
<fileSet>
<directory>${project.basedir}/src/assembly</directory>
<outputDirectory>src/assembly</outputDirectory>
</fileSet>
<fileSet>
<directory>${project.basedir}/src/site</directory>
<outputDirectory>src/site</outputDirectory>
</fileSet>
“`
このDescriptorを使用すると、target/my-app-1.0-sources.zip および target/my-app-1.0-sources.tar.gz が生成され、プロジェクトのソースツリー構造が Assembly内にコピーされます。
ユースケース 3: Executable JAR (Fat JAR) の作成 (Shade Pluginとの比較)
すべての依存関係を単一のJARにまとめる場合。前述の通り、組み込み済みの jar-with-dependencies を使うのが最も簡単です。
“`xml
注意: jar-with-dependencies は依存関係のJARをそのまま展開してクラスファイルをマージします。このとき、同じファイルパスを持つファイル(例: META-INF/services/ ファイルやSpring Bootの spring.factories など)は上書きされる可能性があります。また、異なる依存関係が同じクラス名を持つ場合も問題が発生します。
より堅牢なExecutable JARを作成するには、Maven Shade Plugin の方が適しています。Shade Pluginは、クラスのリロケーション(パッケージ名の変更)、リソースファイルのマージ戦略のカスタマイズ、依存関係のフィルタリングなど、Assembly Pluginの jar 形式 + unpack よりも高度な機能を提供します。Executable JARの作成が主目的であれば、Shade Pluginの利用を検討することを強く推奨します。
簡単にShade Pluginの設定例も示しておきます。
“`xml
Assembly PluginとShade Pluginは、どちらもMaven CentralにあるJARを操作しますが、その目的と機能が異なります。
* Assembly Plugin: 複数のファイル、ディレクトリ、依存関係を、構造化されたディレクトリツリーやアーカイブに「集約(Assemble)」することに特化しています。配布パッケージ作成が得意です。
* Shade Plugin: 複数のJARファイルの中身(クラス、リソース)を単一のJARファイルに「シェード(Shade、影をつける=中に含める)」し、クラス名の変更(リロケーション)やリソースのマージを行いつつ、実行可能なJARを作成することに特化しています。Uber JAR/Fat JAR作成が得意です。
どちらを使うべきかは、実現したいパッケージングの形式によって判断してください。
6. 高度な設定とテクニック
6.1. Assembly ID と出力ファイル名の制御
前述の通り、<id> 要素は出力ファイル名に影響します。デフォルトでは artifactId-version-assemblyId.format という形式になります。
<configuration> 要素内の <appendAssemblyId> を false に設定することで、IDをファイル名に含めないようにできます(例: artifactId-version.format)。この場合、<id> は単にDescriptorを識別するためのものになります。
xml
<configuration>
<descriptors>
<descriptor>src/main/assembly/mydistribution.xml</descriptor>
</descriptors>
<appendAssemblyId>false</appendAssemblyId>
</configuration>
または、<finalName> 要素を使って完全に任意のファイル名を設定することも可能です。
xml
<configuration>
<descriptors>
<descriptor>src/main/assembly/mydistribution.xml</descriptor>
</descriptors>
<finalName>my-application-package-${project.version}</finalName>
</configuration>
この場合、出力ファイルは my-application-package-1.0.zip のようになります。<appendAssemblyId> は無視されます。
6.2. ファイルパーミッションの設定
<fileSets>, <files>, <dependencySets>, <moduleSets> の各要素内で、<permissions> サブ要素を使ってファイルやディレクトリのパーミッション(Unix系システムでのファイルモード)を8進数で指定できます。
xml
<fileSets>
<fileSet>
...
<fileMode>0644</fileMode> <!-- ファイルのパーミッション (rw-r--r--) -->
<directoryMode>0755</directoryMode> <!-- ディレクトリのパーミッション (rwxr-xr-x) -->
</fileSet>
</fileSets>
<files>
<file>
...
<fileMode>0600</fileMode> <!-- ファイルのパーミッション (rw-------) -->
</file>
</files>
<dependencySets>
<dependencySet>
...
<fileMode>0644</fileMode>
</dependencySet>
</dependencySets>
これは特にLinuxやmacOSなどのUnix系システム向けに実行スクリプトの実行権限を設定したい場合に重要です (0755)。Windowsではこれらのパーミッション設定は無視されます。
6.3. プロパティによるフィルタリング
<fileSets> や <files> 要素の <filtered> を true に設定することで、Assemblyに含めるファイルの内容に対してMavenのプロパティ置換を適用できます。例えば、設定ファイル内に ${project.version} や他のプロパティを記述しておき、Assembly作成時に実際の値に置き換えることができます。
src/main/resources/config.properties:
properties
app.version=${project.version}
app.build.timestamp=${maven.build.timestamp}
data.dir=/var/lib/${project.artifactId}
Descriptor (distribution.xml) の <fileSet> 設定:
xml
<fileSet>
<directory>${project.basedir}/src/main/resources</directory>
<outputDirectory>config</outputDirectory>
<includes>
<include>*.properties</include>
</includes>
<filtered>true</filtered> <!-- ここを true にする -->
</fileSet>
これにより、config.properties がAssemblyにコピーされる際に、app.version=1.0, app.build.timestamp=..., data.dir=/var/lib/my-app のように置換されます。
6.4. 依存関係のunpack
<dependencySets> 要素の <unpack> を true に設定すると、指定した依存関係のJARファイルを解凍し、その中身をAssembly内の指定したディレクトリに配置します。
xml
<dependencySets>
<dependencySet>
<outputDirectory>unpacked-lib/some-dep</outputDirectory>
<includes>
<include>com.example:some-dependency:jar</include>
</includes>
<unpack>true</unpack> <!-- JARファイルを解凍 -->
</dependencySet>
</dependencySets>
これは、特定の依存関係のリソースファイルだけを取り出したい場合などに役立つ可能性があります。ただし、前述の通り、Executable JARを作成する目的で依存関係のクラスをまとめるためにこれを使うのは、Shade Pluginよりも柔軟性が劣る場合があります。
6.5. Assemblyをビルド成果物に付与する (attach ゴール)
通常、single ゴールはAssemblyを target ディレクトリに生成しますが、Mavenのビルド成果物としてリポジトリにデプロイしたり、他のモジュールの依存関係として扱ったりしたい場合は、Assemblyをビルド成果物に「付与 (attach)」する必要があります。
これには <goals> 要素で single の代わりに assembly ゴールを使用します(古い情報かもしれません。現行バージョンでは single ゴールでも <attach>true</attach> を使う方が推奨されます)。または、<configuration> 要素内に <attach>true</attach> を指定します。
xml
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.6.0</version>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal> <!-- single ゴールを使用 -->
</goals>
<configuration>
<descriptors>
<descriptor>src/main/assembly/mydistribution.xml</descriptor>
</descriptors>
<attach>true</attach> <!-- ここで true に設定 -->
<!-- <appendAssemblyId>true</appendAssemblyId> --> <!-- デフォルトは true なのでIDがClassifierになる -->
</configuration>
</execution>
</executions>
</plugin>
<attach>true</attach> を指定すると、作成されたAssemblyはMavenの主成果物(通常はプロジェクトのJAR/WAR)に追加の成果物として登録されます。このとき、Assemblyの <id> 要素の値が成果物のClassifierとして使用されます。
例えば、プロジェクトの成果物が my-app-1.0.jar で、AssemblyのIDが distribution であれば、追加の成果物は my-app-1.0-distribution.zip のようになり、他のプロジェクトから依存関係として参照する際にはClassifierに distribution を指定することになります。
xml
<dependency>
<groupId>com.example</groupId>
<artifactId>my-app</artifactId>
<version>1.0</version>
<classifier>distribution</classifier> <!-- Assembly の ID を指定 -->
<type>zip</type> <!-- Assembly のフォーマットを指定 -->
</dependency>
6.6. 特定の依存関係のアーティファクト名変更
<dependencySets> 内で、個々の依存関係の出力ファイル名をカスタマイズしたい場合があります。これは <outputFileNameMapping> 要素で可能です。
xml
<dependencySets>
<dependencySet>
<outputDirectory>lib</outputDirectory>
<scope>runtime</scope>
<outputFileNameMapping>${artifact.artifactId}-${artifact.version}${dashClassifier?}.${artifact.extension}</outputFileNameMapping>
<!-- デフォルトはこの形式 -->
<!-- 別の例: Classifier を含まない -->
<!-- <outputFileNameMapping>${artifact.artifactId}-${artifact.version}.${artifact.extension}</outputFileNameMapping> -->
<!-- 全ての依存関係で同じ名前を使用 (非現実的だが例として) -->
<!-- <outputFileNameMapping>mylibrary.jar</outputFileNameMapping> -->
</dependencySet>
</dependencySets>
outputFileNameMapping 内で使用できる主なプロパティは以下の通りです。
${artifact.artifactId}: 依存関係のartifactId${artifact.version}: 依存関係のversion${artifact.groupId}: 依存関係のgroupId${artifact.extension}: 依存関係の拡張子 (例: jar, war)${artifact.classifier}: 依存関係のclassifier${artifact.scope}: 依存関係のscope${dashClassifier?}: classifierが存在する場合に “-” を出力
これにより、デフォルトの命名規則を変更したり、特定の依存関係のファイル名を固定したりすることができます。
6.7. 空のディレクトリを含める
デフォルトでは、Assembly PluginはDescriptorで定義されていても空のディレクトリは作成しません。Assembly内に特定の空のディレクトリを含めたい場合は、ダミーファイルを含めるか、fileSets や dependencySets の <useStrictFiltering>false</useStrictFiltering> (非推奨または古い設定かもしれません、最新版で確認必要) といった設定を試みる必要があります。しかし、最も確実な方法は、Assembly作成時に空のディレクトリを後から追加するスクリプトを実行することです。Assembly Plugin自体で空のディレクトリだけを作成する直接的な方法は、特定の要素が提供されていない限り難しい場合があります。
7. テストとデバッグ
Assembly Pluginの設定はXMLが複雑になりがちで、パスの指定ミスなどで期待通りに動作しないことがあります。設定を変更したら、必ずビルドを実行してAssemblyが正しく作成されるか確認しましょう。
mvn clean package: Assemblyが作成されます。target/ディレクトリを確認し、Assemblyファイル(ZIP, tar.gzなど)が存在するか確認します。- 作成されたアーカイブファイルを解凍し、中身のファイル構成、ファイル名、ファイルサイズ、そしてUnix系システムの場合はパーミッションが期待通りになっているか確認します。
- フィルタリングを設定した場合は、フィルタリングされたファイルを開いて、プロパティが正しく置換されているか確認します。
- もしExecutable JARを作成した場合は、
java -jar target/your-fat-jar.jarで実行できるか確認します。
デバッグが必要な場合は、Mavenのデバッグオプションを利用すると役立つことがあります。
mvn -X package: デバッグ情報を出力します。Pluginの実行に関する詳細なログが表示され、何がどこからコピーされたか、フィルタリングが適用されたかなどの情報が得られる場合があります。
8. トラブルシューティング
よくある問題と解決策をいくつか紹介します。
- 問題: Assemblyが作成されない、または期待するファイルが含まれていない。
- 確認点:
pom.xmlの<plugin>設定が正しいか。特に<executions>の<phase>と<goals>が適切か。<configuration>で指定したDescriptorファイルへのパスが正しいか。- Descriptor XMLの構文が正しいか。
- Descriptor内の
<fileSets>や<dependencySets>の<directory>,<outputDirectory>,<includes>,<excludes>のパスやパターンが正しいか。特にパスはMavenのプロパティ${project.basedir}や${project.build.directory}からの相対パスとして正しく解釈されているか確認。 - Mavenの出力ログを確認し、Pluginが実行されているか、エラーが出ていないか確認。
- 確認点:
- 問題:
Cannot include project artifactエラーが発生する。- 原因:
<dependencySets>で<useProjectArtifact>false</useProjectArtifact>としているにも関わらず、プロジェクト自身の成果物(JARなど)をAssemblyに含めようとしているか、または<fileSets>などで明示的にプロジェクト成果物を指定していないか。 - 解決策: プロジェクト成果物を含めたい場合は、
<dependencySets>で<useProjectArtifact>true</useProjectArtifact>にするか、<fileSets>で${project.build.directory}/${project.artifactId}-${project.version}.${project.packaging}のように明示的に含める。
- 原因:
- 問題: フィルタリングが機能しない、またはプロパティが置換されない。
- 原因:
<fileSet>または<file>の<filtered>がtrueに設定されていない。または、使用しているプロパティ名が間違っている。 - 解決策:
<filtered>true</filtered>を設定し、プロパティ名が${propertyName}の形式で正しいか確認する。また、プロパティがMavenのビルドプロセスで利用可能であるか確認する。
- 原因:
- 問題: ファイルパーミッションが正しく設定されない。
- 原因: Windowsでビルドしている場合、パーミッション設定は無視されます。これはUnix系システム(Linux, macOS)でのみ有効です。または、8進数の指定が間違っている。
- 解決策: Unix系システムでビルド・確認する。8進数のパーミッション表記が正しいか確認する。
- 問題: Executable JARが実行できない、またはClass Not Foundエラーが出る。
- 原因: Assembly Pluginの
jar-with-dependenciesはクラス名衝突を解決しないため、依存関係に同じ名前のクラスが含まれている場合に問題が発生することがあります。また、META-INF/MANIFEST.MFにMain-Classが正しく設定されていないか、他のリソースファイルがマージされずに失われている可能性があります。 - 解決策: Shade Pluginの使用を検討する。Assembly Pluginを使用する場合は、Descriptorで
<archive>要素を使ってManifestファイルをカスタマイズし、他のリソースファイルのマージ戦略も考慮する必要があります(これはAssembly PluginではShade Pluginほど柔軟ではありません)。
- 原因: Assembly Pluginの
9. まとめ
Maven Assembly Pluginは、Mavenの標準的なパッケージングでは対応できない複雑な配布物やカスタムアーカイブを作成するための非常に強力で柔軟なツールです。アプリケーション配布パッケージ、ソースコードバンドル、特定のファイル群の収集など、様々な用途で活用できます。
- 基本はDescriptor: Assemblyの構成はDescriptorファイル(
assembly.xml)で定義します。 - 主要要素:
<id>,<formats>,<includeBaseDirectory>,<fileSets>,<dependencySets>,<files>などを使って、含めるファイルや依存関係、その配置場所、形式などを細かく制御できます。 - 組み込み済みDescriptor:
jar-with-dependencies,src,binなどの便利なDescriptorが用意されています。 - Executable JAR: Assembly Pluginでも可能ですが、クラスのリロケーションなど高度な機能が必要な場合はMaven Shade Pluginが推奨されます。
- カスタマイズ: ファイルパーミッション、プロパティフィルタリング、ファイル名マッピングなど、詳細な設定が可能です。
- 付与:
<attach>true</attach>でAssemblyをビルド成果物としてリポジトリにデプロイしたり、他のモジュールから参照したりできます。
Assembly Pluginの設定は初めは複雑に感じるかもしれませんが、Descriptorの各要素の役割を理解し、具体的な例を参考にすることで、ほとんどのカスタムパッケージング要件を満たすことができるようになります。
プロジェクトの配布形式に特定の要件がある場合は、ぜひMaven Assembly Pluginの活用を検討してみてください。あなたのビルドプロセスをより柔軟にし、アプリケーションやライブラリの配布を効率化できるでしょう。