Maven Assembly Plugin で配布用JAR/ZIPを作成

はい、承知いたしました。Maven Assembly Plugin を用いた配布用 JAR/ZIP 作成に関する詳細な記事を作成します。約5000字を目指します。


Maven Assembly Plugin で配布用 JAR/ZIP を作成する

はじめに

ソフトウェア開発において、ビルドプロセスはコードのコンパイル、テスト、そして配布可能な成果物の作成という重要な役割を担います。Java プロジェクトの場合、Maven は標準的なビルドツールとして広く利用されており、これらのプロセスを効率化します。特に、開発したアプリケーションをユーザーや他のシステムに配布する際には、単に実行可能な JAR ファイルだけでなく、依存ライブラリ、設定ファイル、実行スクリプト、ドキュメントなどをまとめて整理した形で提供することが求められます。

このような配布物を作成するために、Maven は様々なプラグインを提供していますが、その中でも最も柔軟で強力なツールの一つが Maven Assembly Plugin です。このプラグインを使用することで、プロジェクトの成果物、依存ライブラリ、およびプロジェクト外の任意のファイル群を組み合わせて、単一の JAR ファイル(いわゆる “fat JAR” や “shaded JAR” のような形式、ただし Assembly Plugin は Shaded Plugin とは異なるアプローチをとります)、ZIP ファイル、TAR.GZ ファイルなどのアーカイブ形式にパッケージングすることができます。

この記事では、Maven Assembly Plugin の基本的な使い方から、アセンブリディスクリプタと呼ばれる設定ファイルの詳細、様々な配布物形式の作成例、そして高度な設定に至るまで、Assembly Plugin を活用して配布物を自在に作成する方法を詳細に解説します。

記事の目的と対象読者

  • Maven を使用した Java プロジェクトの開発者。
  • 開発したアプリケーションの配布物作成プロセスを自動化・標準化したいと考えている方。
  • Assembly Plugin の設定方法や機能について、より深く理解したい方。

この記事を読むことで、以下のことができるようになります。

  • Maven Assembly Plugin をプロジェクトに導入し、基本的なアセンブリを実行する。
  • アセンブリディスクリプタ XML ファイルの構造と主要な要素を理解する。
  • プロジェクトの特性や配布形式の要件に応じたカスタムアセンブリディスクリプタを作成する。
  • 実行可能 JAR、依存ライブラリを含む ZIP、ソースコードアーカイブなど、様々な形式の配布物を作成する。
  • Assembly Plugin の高度な設定(フィルタリング、権限設定、複数のアセンブリ実行など)を利用する。
  • よくある問題の解決方法を学ぶ。

Maven Assembly Plugin の基本

Maven Assembly Plugin を使用するには、まずプロジェクトの pom.xml にプラグイン定義を追加する必要があります。

xml
<project>
...
<build>
<plugins>
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.6.0</version> <!-- 最新バージョンを使用することを推奨 -->
<configuration>
<!-- グローバルな設定をここに記述 -->
<!-- 例: デフォルトの出力ディレクトリを指定 -->
<!-- <outputDirectory>${project.build.directory}/my-dist</outputDirectory> -->
</configuration>
<executions>
<!-- アセンブリを実行するタイミングと設定 -->
<execution>
<id>make-assembly</id> <!-- 実行IDは任意 -->
<phase>package</phase> <!-- 通常は package フェーズにバインド -->
<goals>
<goal>single</goal> <!-- single ゴールを実行 -->
</goals>
<configuration>
<!-- この execution に固有の設定 -->
<!-- 例: 使用するアセンブリディスクリプタファイルを指定 -->
<descriptors>
<descriptor>src/main/assembly/distribution.xml</descriptor>
</descriptors>
<!-- あるいは、標準のディスクリプタIDを指定 -->
<!-- <descriptorRefs>
<descriptorRef>bin</descriptorRef>
</descriptorRefs> -->
</configuration>
</execution>
<!-- 必要に応じて他の execution を追加 -->
</executions>
</plugin>
...
</plugins>
</build>
...
</project>

プラグインの導入

上記の例のように、<plugin> 要素を <build><plugins> セクションに追加します。<groupId>org.apache.maven.plugins<artifactId>maven-assembly-plugin です。<version> には使用したい Assembly Plugin のバージョンを指定します。記事執筆時点での最新バージョンは 3.6.0 ですが、常に Maven 公式サイトや中央リポジトリで最新安定版を確認することを推奨します。

基本的な設定要素

  • <configuration>: プラグイン全体、または <execution> ごとに適用される設定を記述します。例えば、出力ディレクトリの指定や、アセンブリディスクリプタの指定などを行います。
  • <executions>: アセンブリを実行するタイミング(Maven のビルドフェーズ)や、具体的な設定を複数定義できます。通常、<execution> 要素を一つ以上定義し、ビルドフェーズ (<phase>) にバインドします。
  • <execution>: 特定のビルドフェーズに関連付けられたアセンブリ設定の単位です。
    • <id>: この実行を一意に識別するための ID です。複数の実行を定義する場合に重要になります。
    • <phase>: この実行をバインドする Maven のビルドフェーズを指定します。一般的には package フェーズに設定することが多いです。このフェーズでは、プロジェクトの成果物 (JAR や WAR ファイルなど) が既に作成されています。
    • <goals>: この実行でどの Assembly Plugin のゴールを実行するかを指定します。最もよく使われるゴールは single です。
      • single: 指定されたディスクリプタに基づいて、単一のアセンブリ(ZIP、TAR、JARなど)を作成します。
      • help: プラグインのヘルプ情報を表示します。

アセンブリディスクリプタ (descriptor / descriptorRef)

Assembly Plugin の最も重要な概念は アセンブリディスクリプタ (Assembly Descriptor) です。これは XML 形式のファイルで、どのようなファイルや依存ライブラリを、配布物内のどこに、どのような形式で含めるかを定義します。

ディスクリプタを指定する方法は主に二つあります。

  1. カスタムディスクリプタファイルの指定 (<descriptors>): プロジェクト内に独自のディスクリプタファイルを作成し、そのパスを指定します。
    xml
    <descriptors>
    <descriptor>src/main/assembly/distribution.xml</descriptor>
    </descriptors>

    この方法が最も一般的で柔軟性が高いです。通常、src/main/assembly/ ディレクトリ以下に *.xml ファイルとして配置します。
  2. 標準ディスクリプタ ID の参照 (<descriptorRefs>): Assembly Plugin が内部的に提供する、いくつかの標準的なディスクリプタを参照します。
    xml
    <descriptorRefs>
    <descriptorRef>bin</descriptorRef>
    </descriptorRefs>

    利用可能な標準 ID には bin, src, project, assembly などがあります。これらは基本的な配布物(バイナリ、ソース、プロジェクト全体など)を迅速に作成するために用意されていますが、内容は固定されているため、カスタマイズには向きません。特殊な要件がない限り、カスタムディスクリプタを使用することを推奨します。

アセンブリディスクリプタ (Assembly Descriptor) の詳細

アセンブリディスクリプタは、配布物の内容と構造を定義する XML ファイルです。ルート要素は <assembly> で、その中に様々な設定要素を記述します。ディスクリプタの基本的な構造と主要な要素について詳しく見ていきましょう。

“`xml

<id>my-dist</id> <!-- アセンブリの識別子 -->

<formats> <!-- 出力形式 -->
    <format>zip</format>
    <format>tar.gz</format>
</formats>

<includeBaseDirectory>true</includeBaseDirectory> <!-- ルートディレクトリを含めるか -->
<baseDirectory>${project.artifactId}-${project.version}</baseDirectory> <!-- ルートディレクトリ名 -->

<fileSets> <!-- プロジェクト内のファイル群を追加 -->
    ...
</fileSets>

<dependencySets> <!-- 依存ライブラリを追加 -->
    ...
</dependencySets>

<moduleSets> <!-- マルチモジュールプロジェクトで他のモジュールの成果物を追加 -->
    ...
</moduleSets>

<files> <!-- 個別のファイルを追加 -->
    ...
</files>

<!-- components 要素や repositories 要素なども存在する -->


“`

主要な要素

  • <id>: (必須) このアセンブリディスクリプタを一意に識別する ID です。この ID は、作成される配布物のファイル名の一部として使用されることが一般的です(例: artifactId-version-id.zip)。
  • <formats>: (必須) 作成する配布物のアーカイブ形式を指定します。複数の形式を指定できます。
    • <format>: 利用可能な形式は jar, zip, tar, tar.gz, tar.bz2, dir (ディレクトリ構造として出力、アーカイブしない), jxr, war, swc などがあります。一般的には ziptar.gz が配布物、jar が単一JAR(Shaded JAR風)に使われます。
  • <includeBaseDirectory>: (オプション) 作成されるアーカイブのルートに、単一のベースディレクトリを含めるかどうかを指定します。デフォルトは true です。true の場合、アーカイブを展開すると、指定した名前のディレクトリができ、その中にコンテンツが配置されます。false の場合、コンテンツがアーカイブのルートに直接配置されます。JAR ファイルを作成する場合は通常 false にします。
  • <baseDirectory>: (オプション) <includeBaseDirectory>true の場合に、ルートディレクトリの名前を指定します。Maven プロパティ(${project.artifactId}, ${project.version} など)を利用して、プロジェクト名とバージョンを含む名前にすることが一般的です。例: ${project.artifactId}-${project.version}
  • <fileSets>: (オプション) プロジェクトのディレクトリ構造内の特定のファイルやディレクトリ群を、配布物の指定された場所に追加するための設定です。複数の <fileSet> 要素を定義できます。
    • <fileSet>: 個々のファイルセットの定義です。
      • <directory>: (必須) 対象となるディレクトリのパスです。プロジェクトのベースディレクトリからの相対パスを指定します。例: src/main/resources, src/main/bin, . (プロジェクトルート)
      • <outputDirectory>: (必須) 配布物内の、このファイルセットの内容がコピーされる場所のパスです。アーカイブのルートからの相対パスを指定します。例: /config, /bin, / (ルート)
      • <includes>: (オプション) <directory> 内で含めるファイル/ディレクトリのパターンをリストします。<include> 要素でパターンを指定します(例: *.properties, **/*.sh)。指定しない場合は、<directory> 内のすべてのファイル/ディレクトリが対象になります(<excludes> で除外されない限り)。
      • <excludes>: (オプション) <directory> 内で除外するファイル/ディレクトリのパターンをリストします。<exclude> 要素でパターンを指定します(例: *.bak, temp/, target/)。<includes> よりも優先されます。
      • <filtered>: (オプション) このファイルセット内のファイルに対して Maven のリソースフィルタリングを適用するかどうかを指定します (true または false)。デフォルトは false です。
      • <nonFilteredFileExtensions>: (オプション) <filtered>true の場合でも、フィルタリングを適用しないファイルの拡張子を指定します。バイナリファイルなどで誤ってフィルタリングされないようにします。
      • <lineEnding>: (オプション) コピー時にファイルの改行コードを変換するかどうかを指定します。利用可能な値は keep (変換しない), unix, dos, windows です。
      • <fileMode>, <directoryMode>: (オプション) TAR または ZIP アーカイブにおいて、コピーされるファイル/ディレクトリのパーミッション(Unix モード)を設定します。3桁または4桁の8進数で指定します(例: 0644, 0755)。
  • <dependencySets>: (オプション) プロジェクトの依存ライブラリを、配布物の指定された場所に追加するための設定です。複数の <dependencySet> 要素を定義できます。
    • <dependencySet>: 個々の依存ライブラリセットの定義です。
      • <outputDirectory>: (必須) 配布物内の、依存ライブラリがコピーされる場所のパスです。例: /lib
      • <useProjectArtifact>: (オプション) プロジェクト自身の成果物(デフォルトでは JAR ファイル)をこのセットに含めるかどうかを指定します (true または false)。デフォルトは true です。
      • <useTransitiveDependencies>: (オプション) 推移的な依存関係(依存ライブラリがさらに依存しているライブラリ)を含めるかどうかを指定します (true または false)。デフォルトは true です。
      • <includes>, <excludes>: (オプション) 含める/除外する依存ライブラリを指定します。groupId:artifactId:type:classifier または groupId:artifactId の形式で指定します。例: <include>com.example:my-library:jar</include>, <exclude>commons-logging:commons-logging</exclude>
      • <unpack>: (オプション) コピーされる依存ライブラリ(主に JAR や WAR)を展開して追加するかどうかを指定します (true または false)。デフォルトは false です。実行可能 JAR を作成する際に、依存ライブラリのクラスファイルをすべて単一の JAR に含めたい場合などに true に設定します。ただし、これはクラス名の衝突などの問題を引き起こす可能性があるため注意が必要です。
      • <scope>: (オプション) 含める依存関係のスコープを指定します。<scope>compile</scope>, <scope>runtime</scope>, <scope>provided</scope>, <scope>test</scope>, <scope>system など。複数のスコープを含める場合は <scope>compile,runtime</scope> のようにカンマ区切りで指定します。デフォルトは runtime スコープです。
  • <moduleSets>: (オプション) マルチモジュールプロジェクトにおいて、他のモジュールの成果物(JAR、ソースなど)を配布物に追加するための設定です。複数の <moduleSet> 要素を定義できます。
    • <moduleSet>: 個々のモジュールセットの定義です。
      • <includes>, <excludes>: 含める/除外するモジュールを groupId:artifactId の形式で指定します。
      • <binaries>: モジュールのバイナリ成果物(通常は JAR)を含める設定です。<outputDirectory>, <unpack>, <includes>, <excludes> (classifierなど) などのサブ要素を持ちます。
      • <sources>: モジュールのソースコードを含める設定です。<outputDirectory>, <includes>, <excludes> などのサブ要素を持ちます。
  • <files>: (オプション) プロジェクト外を含む、特定の個別のファイルを配布物に追加するための設定です。複数の <file> 要素を定義できます。
    • <file>: 個々のファイルの定義です。
      • <source>: (必須) コピー元ファイルのパスです。プロジェクトのベースディレクトリからの相対パスでも、絶対パスでも指定できます。
      • <outputDirectory>: (必須) 配布物内の、ファイルがコピーされるディレクトリのパスです。
      • <destName>: (オプション) 配布物内でのファイル名です。指定しない場合は元のファイル名が使用されます。
      • <filtered>, <lineEnding>, <fileMode> など、<fileSets><fileSet> と同様のサブ要素を持ちます。

カスタムディスクリプタの作成と使用例

ここからは、具体的な配布物の形式に合わせてカスタムディスクリプタを作成し、それを使ってアセンブリを実行する例を見ていきます。

例1: 依存ライブラリを単一の JAR にまとめる (Shaded JAR に近い形式)

この例では、プロジェクト自身のクラスファイルと、依存ライブラリのクラスファイルをすべて展開して、単一の実行可能 JAR ファイルを作成します。これは Maven Shade Plugin の機能に似ていますが、Assembly Plugin はクラスのリロケーションや競合解決の機能は持たないため、単純なケースや競合が発生しない場合に適しています。

ただし、クラスパスやファイル名の衝突が発生する可能性があるため、より堅牢な単一実行可能 JAR を作成する場合は、Shade Plugin を検討することを強く推奨します。

ディスクリプタファイル (src/main/assembly/standalone-jar.xml):

“`xml

<id>standalone</id> <!-- 出力ファイル名は artifactId-version-standalone.jar となる -->

<formats>
    <format>jar</format>
</formats>

<includeBaseDirectory>false</includeBaseDirectory> <!-- JAR のルートに直接コンテンツを配置 -->

<dependencySets>
    <dependencySet>
        <outputDirectory>/</outputDirectory> <!-- JAR のルートに展開 -->
        <unpack>true</outputDirectory> <!-- 依存 JAR の中身を展開 -->
        <scope>runtime</scope> <!-- ランタイム依存を含める -->
        <useProjectArtifact>true</useProjectArtifact> <!-- プロジェクト自身の成果物 (classes) も含める -->
    </dependencySet>
</dependencySets>

<!-- 必要に応じてリソースなども含める -->
<fileSets>
    <fileSet>
        <directory>${project.basedir}/src/main/resources</directory>
        <outputDirectory>/</outputDirectory> <!-- JAR のルートに配置 -->
        <includes>
            <include>**/*</include>
        </includes>
    </fileSet>
</fileSets>


“`

pom.xml の設定:

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-standalone-jar</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptors>
<descriptor>src/main/assembly/standalone-jar.xml</descriptor>
</descriptors>
<!-- 実行可能JARにするための MANIFEST.MF 設定 (Optional) -->
<archive>
<manifest>
<mainClass>com.yourpackage.MainClass</mainClass>
</manifest>
</archive>
</configuration>
</execution>
</executions>
</plugin>
...
</plugins>
</build>
...
</project>

pom.xml<archive><manifest><mainClass> 設定は、java -jar コマンドで直接実行可能な JAR にするために必要です。Assembly Plugin は MANIFEST.MF を生成・更新する機能も持っています。

実行: mvn package または mvn assembly:single

これにより、target/ ディレクトリに artifactId-version-standalone.jar という名前の JAR ファイルが作成されます。

例2: 依存ライブラリを分離した ZIP 配布物

この例では、アプリケーションの JAR ファイル、依存ライブラリ、設定ファイル、実行スクリプトなどを、それぞれ別のディレクトリに配置して ZIP アーカイブを作成します。これは、依存ライブラリの管理が容易で、クラスパスを制御しやすい配布形式です。

プロジェクト構造例:

my-app/
├── pom.xml
└── src/
├── main/
│ ├── java/
│ │ └── com/yourpackage/MainClass.java
│ ├── resources/
│ │ └── application.properties
│ └── bin/
│ ├── run.sh
│ └── run.bat
└── main/assembly/
└── distribution.xml

ディスクリプタファイル (src/main/assembly/distribution.xml):

“`xml

<id>dist</id> <!-- 出力ファイル名は artifactId-version-dist.zip となる -->

<formats>
    <format>zip</format>
    <format>tar.gz</format> <!-- 必要なら tar.gz も追加 -->
</formats>

<includeBaseDirectory>true</includeBaseDirectory> <!-- ベースディレクトリを含める -->
<baseDirectory>${project.artifactId}-${project.version}</baseDirectory> <!-- ディレクトリ名 -->

<!-- 実行スクリプトを bin ディレクトリにコピー -->
<fileSets>
    <fileSet>
        <directory>${project.basedir}/src/main/bin</directory>
        <outputDirectory>bin</outputDirectory> <!-- 配布物内の bin ディレクトリ -->
        <includes>
            <include>run.sh</include>
            <include>run.bat</include>
        </includes>
        <!-- Unix系環境での実行権限を設定 -->
        <fileMode>0755</fileMode>
        <!-- 改行コードを Unix 形式に変換 (Windowsで編集した場合など) -->
        <lineEnding>unix</lineEnding>
    </fileSet>

    <!-- 設定ファイルやその他のリソースを config ディレクトリにコピー -->
    <fileSet>
        <directory>${project.basedir}/src/main/resources</directory>
        <outputDirectory>config</outputDirectory> <!-- 配布物内の config ディレクトリ -->
        <includes>
            <include>**/*</include>
        </includes>
        <!-- 必要ならフィルタリングを有効にする -->
        <!-- <filtered>true</filtered> -->
    </fileSet>

    <!-- README や LICENSE ファイルなどをルートにコピー -->
    <fileSet>
        <directory>${project.basedir}</directory>
        <outputDirectory>/</outputDirectory> <!-- 配布物内のルート -->
        <includes>
            <include>README*</include>
            <include>LICENSE*</include>
        </includes>
    </fileSet>
</fileSets>

<!-- 依存ライブラリを lib ディレクトリにコピー -->
<dependencySets>
    <dependencySet>
        <outputDirectory>lib</outputDirectory> <!-- 配布物内の lib ディレクトリ -->
        <useProjectArtifact>true</useProjectArtifact> <!-- プロジェクト自身のJARも lib に含める -->
        <unpack>false</unpack> <!-- 依存 JAR は展開せずそのままコピー -->
        <scope>runtime</scope> <!-- ランタイム依存を含める -->
        <!-- 必要なら特定の依存を除外/含める -->
        <!-- <excludes>
             <exclude>log4j:log4j</exclude>
        </excludes> -->
    </dependencySet>
</dependencySets>


“`

pom.xml の設定:

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-distribution</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptors>
<descriptor>src/main/assembly/distribution.xml</descriptor>
</descriptors>
</configuration>
</execution>
</executions>
</plugin>
...
</plugins>
</build>
...
</project>

実行: mvn package または mvn assembly:single

これにより、target/ ディレクトリに artifactId-version-dist.zip (および artifactId-version-dist.tar.gz) ファイルが作成されます。このアーカイブを展開すると、例えば my-app-1.0.0-SNAPSHOT/ ディレクトリができ、その中に bin/, config/, lib/, README.md などのファイル/ディレクトリが配置されます。

bin/run.sh (例):

“`bash

!/bin/bash

Change to the distribution directory

cd “$(dirname “$0″)/..”

Set classpath to include all JARs in the lib directory

CP=./config
for i in ./lib/*.jar; do
CP=$CP:$i
done

Execute the main class

java -cp “$CP” com.yourpackage.MainClass “$@”
“`

bin/run.bat (例):

“`batch
@echo off
REM Change to the distribution directory
cd /d “%~dp0..”

REM Set classpath to include all JARs in the lib directory
set CP=.\config
for %%i in (.\lib*.jar) do (
set CP=%%i;%CP%
)

REM Execute the main class
java -cp “%CP%” com.yourpackage.MainClass %*
“`

例3: ソースコード配布物

この例では、プロジェクトのソースコード、pom.xml、README、LICENSE などのファイルをまとめて、ZIP または TAR.GZ アーカイブを作成します。これは、他の開発者にソースコードを提供したり、SonaType Nexus などのリポジトリにソース JAR をアップロードしたりする場合に役立ちます。

ディスクリプタファイル (src/main/assembly/src.xml):

“`xml

<id>sources</id> <!-- 出力ファイル名は artifactId-version-sources.zip/tar.gz となる -->

<formats>
    <format>zip</format>
    <format>tar.gz</format>
</formats>

<includeBaseDirectory>true</includeBaseDirectory>
<baseDirectory>${project.artifactId}-${project.version}-sources</baseDirectory>

<fileSets>
    <!-- プロジェクトルートのファイルを含める -->
    <fileSet>
        <directory>${project.basedir}</directory>
        <outputDirectory>/</outputDirectory>
        <includes>
            <include>pom.xml</include>
            <include>README*</include>
            <include>LICENSE*</include>
        </includes>
        <!-- 不要なファイルを念のため除外 -->
        <excludes>
            <exclude>target/**</exclude>
            <exclude>.git/**</exclude>
            <exclude>.idea/**</exclude>
            <exclude>*.iml</exclude>
        </excludes>
    </fileSet>

    <!-- src ディレクトリ以下のすべてのソース関連ファイルを含める -->
    <fileSet>
        <directory>${project.basedir}/src</directory>
        <outputDirectory>src</outputDirectory>
        <includes>
            <include>**/*</include>
        </includes>
        <excludes>
            <!-- ビルド生成物や一時ファイルなどを除外 -->
            <exclude>target/**</exclude>
            <exclude>assembly/**</exclude> <!-- アセンブリディスクリプタ自身は含めない場合 -->
        </excludes>
    </fileSet>
</fileSets>


“`

pom.xml の設定:

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-source-archive</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptors>
<descriptor>src/main/assembly/src.xml</descriptor>
</descriptors>
</configuration>
</execution>
</executions>
</plugin>
<!-- 通常、ソースJARは maven-source-plugin で生成されることが多いです。 -->
<!-- こちらは配布用アーカイブとしての例です。 -->
<!-- maven-source-plugin を使う場合は以下の設定 -->
<!--
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.3.0</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
-->
...
</plugins>
</build>
...
</project>

実行: mvn package または mvn assembly:single

これにより、target/ ディレクトリに artifactId-version-sources.zip および artifactId-version-sources.tar.gz が作成されます。

例4: 標準ディスクリプタ ID の使用

Assembly Plugin はいくつかの標準ディスクリプタを提供しています。これらを利用すると、カスタムディスクリプタファイルを作成せずに基本的な配布物を作成できます。ただし、内容は固定されており、カスタマイズはできません。

利用可能な主な標準ディスクリプタ ID:

  • bin: プロジェクトのバイナリ成果物 (JARなど) とその依存ライブラリを、それぞれ別のディレクトリに配置したアーカイブ。例2のカスタムディスクリプタに似ています。
  • src: プロジェクトのソースコード、pom.xml、README、LICENSEなどをまとめたアーカイブ。例3のカスタムディスクリプタに似ています。
  • project: binsrc の両方を含む、プロジェクト全体をまとめたアーカイブ。
  • assembly: 中身が空のアーカイブ。カスタムディスクリプタのベースとして利用されることがあります。

pom.xml での指定例:

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-standard-bin</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptorRefs>
<descriptorRef>bin</descriptorRef> <!-- 標準の 'bin' ディスクリプタを使用 -->
</descriptorRefs>
</configuration>
</execution>
<!-- 複数の標準ディスクリプタを生成する場合 -->
<!-- <execution>
<id>make-standard-src</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptorRefs>
<descriptorRef>src</descriptorRef>
</descriptorRefs>
</configuration>
</execution> -->
</executions>
</plugin>
...
</plugins>
</build>
...
</project>

実行: mvn package または mvn assembly:single

これにより、target/ ディレクトリに artifactId-version-bin.zip (または他のデフォルト形式) が作成されます。標準ディスクリプタは <formats> や他の詳細な設定をプラグイン定義側でオーバーライドできない場合があるため、注意が必要です。ほとんどの場合、カスタムディスクリプタを使用する方が推奨されます。

Assembly Plugin の高度な設定と応用

複数のアセンブリを作成する

前述の <executions> 要素を利用することで、一つの pom.xml 定義で複数の異なるアセンブリを作成することができます。例えば、ZIP 形式と TAR.GZ 形式の両方を作成したり、依存ライブラリ分離型 ZIP とソースコードアーカイブの両方を作成したりする場合です。

xml
<project>
...
<build>
<plugins>
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.6.0</version>
<executions>
<!-- 依存ライブラリ分離型 ZIP/TAR.GZ アセンブリ -->
<execution>
<id>make-distribution</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptors>
<descriptor>src/main/assembly/distribution.xml</descriptor>
</descriptors>
</configuration>
</execution>
<!-- ソースコードアーカイブ アセンブリ -->
<execution>
<id>make-source-archive</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptors>
<descriptor>src/main/assembly/src.xml</descriptor>
</descriptors>
</configuration>
</execution>
</executions>
</plugin>
...
</plugins>
</build>
...
</project>

上記の例では、mvn package コマンドを実行すると、distribution.xmlsrc.xml の両方のディスクリプタに基づいてアセンブリが作成されます。

フィルタリングの活用

<fileSets><files> 要素の <filtered>true</filtered> 設定を有効にすることで、Maven のリソースフィルタリング機能を活用できます。これは、設定ファイルなどにプロジェクトのバージョン情報や外部プロパティを埋め込みたい場合に非常に便利です。

  1. プロパティファイルの準備: 例えば src/main/filters/filter.properties のようなファイルに、フィルタリングに使用するプロパティを定義します。
    properties
    app.version=${project.version}
    app.name=${project.artifactId}
    build.timestamp=${maven.build.timestamp}

    ${project.version} のような標準 Maven プロパティも使用できます。
  2. pom.xml でフィルタリングを有効化: pom.xml<build> セクションに <filters> 要素と <resources> 要素を追加し、プロパティファイルとフィルタリング対象のリソースディレクトリを指定します。
    xml
    <build>
    <filters>
    <filter>src/main/filters/filter.properties</filter>
    </filters>
    <resources>
    <resource>
    <directory>src/main/resources</directory>
    <filtering>true</filtering> <!-- ここでリソースディレクトリ全体のフィルタリングを有効化 -->
    <includes>
    <include>**/*.properties</include> <!-- 例: .properties ファイルだけフィルタリング対象にする -->
    </includes>
    </resource>
    <resource>
    <directory>src/main/resources</directory>
    <filtering>false</filtering> <!-- フィルタリングしないリソース -->
    <excludes>
    <exclude>**/*.properties</exclude>
    </excludes>
    </resource>
    </resources>
    <plugins>
    ...
    </plugins>
    </build>

    注意: ここで <resource><filtering>true</filtering> を設定すると、ビルドプロセス自体で src/main/resources 内のファイルがフィルタリングされ、target/classes ディレクトリにコピーされます。Assembly Plugin の <fileSets> でその target/classes ディレクトリをコピーする場合、Assembly Plugin 側で再度 <filtered>true</filtered> を指定する必要はありません(二重フィルタリングになる可能性がある)。Assembly Plugin の <fileSets><filtered>true</filtered> を使うのは、リソースディレクトリ以外(例: src/main/config)のファイルをフィルタリングしたい場合や、ビルドプロセス全体ではなくアセンブリ時のみフィルタリングしたい場合に便利です。
  3. ディスクリプタでフィルタリングを有効化: フィルタリングしたいファイルが含まれる <fileSet> または <file> 要素に <filtered>true</filtered> を追加します。

    xml
    <fileSet>
    <directory>${project.basedir}/src/main/config</directory>
    <outputDirectory>config</outputDirectory>
    <includes>
    <include>app.properties</include>
    </includes>
    <filtered>true</filtered> <!-- Assembly Plugin でフィルタリングを有効化 -->
    </fileSet>

    src/main/config/app.properties の内容例:
    properties
    version=${app.version}
    name=${app.name}
    built=${build.timestamp}

    Assembly Plugin がこのファイルをコピーする際に、上記のプロパティが実際の値に置換されます。

依存関係の詳細な制御

<dependencySets> 要素では、<includes><excludes><scope> などの要素を使って、配布物に含める依存ライブラリを細かく制御できます。

  • 特定のライブラリを除外:
    xml
    <dependencySet>
    ...
    <excludes>
    <exclude>log4j:log4j</exclude> <!-- log4j を除外 -->
    <exclude>org.slf4j:*</exclude> <!-- SLF4J ファサードをすべて除外 -->
    <exclude>*:*:${project.packaging}:tests</exclude> <!-- Test JAR を除外 -->
    </excludes>
    </dependencySet>
  • 特定のスコープのライブラリのみ含める:
    xml
    <dependencySet>
    ...
    <scope>runtime</scope> <!-- runtime スコープのみ -->
    </dependencySet>
  • classifier を指定して含める: javadoc や sources JAR など、デフォルトの成果物以外の classifier を持つ依存ライブラリを含めることができます。
    xml
    <dependencySet>
    ...
    <includes>
    <include>${project.groupId}:${project.artifactId}:${project.packaging}:sources</include> <!-- 自身のソース JAR を含める -->
    <include>com.example:my-library:jar:javadoc</include> <!-- 別のライブラリの javadoc JAR を含める -->
    </includes>
    <outputDirectory>docs/javadoc</outputDirectory>
    </dependencySet>

ファイル権限の設定 (fileMode, directoryMode)

UNIX 系環境で実行可能なスクリプトなどを配布物に含める場合、適切な実行権限 (0755 など) を設定することが重要です。<fileSets><files> 要素の <fileMode> および <directoryMode> を使用します。

“`xml

${project.basedir}/src/main/bin
bin

run.sh

0755


${project.basedir}/src/main/config
config
0755

“`
これらの設定は、TAR または ZIP アーカイブにのみ有効です。JAR ファイルはファイル権限の概念を持ちません。

Maven Property の利用

ディスクリプタ内の多くの場所で、${project.*}${session.*} などの Maven プロパティを利用できます。これにより、バージョン番号や成果物 ID を動的にファイル名やディレクトリパスに含めることができます。また、カスタムプロパティを <properties> セクションなどで定義し、それを利用することも可能です。

xml
<assembly>
...
<baseDirectory>${project.artifactId}-${project.version}</baseDirectory>
...
<fileSets>
<fileSet>
<directory>${project.build.directory}/classes</directory> <!-- ビルド成果物ディレクトリを参照 -->
<outputDirectory>app</outputDirectory>
</fileSet>
</fileSets>
</assembly>

他のプラグインとの連携と使い分け

  • Maven Shade Plugin: 前述の通り、単一の実行可能 JAR (Fat JAR/Shaded JAR) を作成する場合、依存ライブラリのクラス名の衝突を解決したり、特定のエントリを除外・変換したりする機能が必要であれば、Assembly Plugin よりも Shade Plugin の方が適しています。Assembly Plugin は単純なファイル/ディレクトリコピーや、JAR 展開によるクラス取り込みには使えますが、高度な変換や競合解決は行いません。
  • Maven Dependency Plugin: このプラグインは、依存ライブラリを特定のディレクトリにコピーしたり、解凍したりすることに特化しています。もし配布物作成の一部分として依存ライブラリの操作だけが必要な場合は、Dependency Plugin の方がシンプルかもしれません。しかし、依存ライブラリの配置とその他のファイルの配置をまとめて制御したい場合は、Assembly Plugin が便利です。Assembly Plugin の <dependencySets> は、内部的に Dependency Plugin の機能を利用している側面もあります。

多くの場合、Assembly Plugin はプロジェクト全体の最終的な配布物パッケージングに、Shade Plugin は単一の実行可能 JAR 作成に、Dependency Plugin はビルド中間での依存ライブラリ操作に使用されることが多いです。

トラブルシューティング

Assembly Plugin の設定は柔軟性が高い反面、意図しない結果になることもあります。以下によくある問題とその解決策を挙げます。

  • 作成されたアーカイブにファイルが含まれていない、または意図しないファイルが含まれている:
    • <fileSets><files><directory>, <source> パスが正しいか確認してください。プロジェクトルートからの相対パスが一般的です。
    • <includes>, <excludes> パターンが正しく記述されているか確認してください。ワイルドカード (*, **) の使い方や、指定するファイル名・ディレクトリ名がパターンに一致しているか確認します。<excludes><includes> より優先されることに注意してください。
    • <outputDirectory> が正しい配布物内のパスを指定しているか確認してください。
    • <dependencySets><scope> 設定が意図した依存関係を含めるようになっているか確認してください。デフォルトは runtime です。test スコープの依存はデフォルトでは含まれません。
    • <useProjectArtifact>true になっていて、プロジェクト自身の JAR が含まれるようになっているか確認してください (依存ライブラリ分離型の場合)。
    • <unpack>true になっていて、期待通りに依存 JAR が展開されているか確認してください (単一 JAR の場合)。
  • 作成されたアーカイブの構造が意図したものと違う:
    • <includeBaseDirectory><baseDirectory> の設定を確認してください。ベースディレクトリが必要か、その名前が正しいか。
    • <fileSet>, <dependencySet>, <file><outputDirectory> が、配布物内の正しい場所を示しているか確認してください。これはベースディレクトリからの相対パスになります(ベースディレクトリがない場合はアーカイブのルートからの相対パス)。
  • フィルタリングが適用されない、または予期せず適用される:
    • フィルタリングを適用したい <fileSet> または <file><filtered>true</filtered> が設定されているか確認してください。
    • <pom.xml><build><filters> および <resources> 設定で、フィルタリング対象のプロパティファイルとリソースディレクトリが正しく指定されているか確認してください。
    • フィルタリング対象とすべきでないバイナリファイルなどがフィルタリングされて破損していないか確認し、必要に応じて <nonFilteredFileExtensions> を設定してください。
  • Windows と Linux での動作の違い:
    • 実行スクリプトなどの改行コード (\r\n vs \n) は <lineEnding> 設定で明示的に指定することをお勧めします。
    • ファイルパスの区切り文字 (\ vs /) は、Assembly Plugin の設定では基本的に / を使用するのが安全です。Maven が内部的にプラットフォームに合わせて変換してくれます。
    • ファイル権限 (<fileMode>, <directoryMode>) は TAR/ZIP でのみ有効であり、Windows では無視されるか、変換される場合があります。
  • クラスパスの問題 (単一 JAR の実行時):
    • java -jar で実行したい場合、MANIFEST.MF に Main-Class エントリが正しく設定されているか確認してください (pom.xml<archive><manifest><mainClass> または他の Maven プラグイン設定)。
    • 依存ライブラリが JAR に含まれていない場合 (unpack=false)、java -jar では標準では依存 JAR は読み込まれません。依存ライブラリ分離型の場合は、実行スクリプトでクラスパスを正しく指定する必要があります (java -cp "lib/*" など)。

これらの問題を解決するためには、まず mvn package -X (デバッグログ出力) を実行して、Assembly Plugin がどのように動作しているか、どのファイルがどこからコピーされ、どこに配置されているかを確認することが役立ちます。

まとめ

Maven Assembly Plugin は、Java プロジェクトの配布物作成において非常に強力で柔軟なツールです。アセンブリディスクリプタ XML ファイルを記述することで、プロジェクトの成果物、依存ライブラリ、および任意の外部ファイルを組み合わせて、様々な形式(JAR, ZIP, TAR.GZ など)のアーカイブを作成できます。

この記事では、プラグインの導入方法から始まり、アセンブリディスクリプタの主要な要素(<id>, <formats>, <fileSets>, <dependencySets> など)を詳細に解説しました。さらに、実行可能 JAR、依存ライブラリ分離型 ZIP、ソースコードアーカイブといった具体的な配布物形式の作成例を通して、カスタムディスクリプタの記述方法を学びました。最後に、複数のアセンブリ作成、フィルタリング、依存関係の詳細な制御、ファイル権限設定、他のプラグインとの連携といった高度なトピック、そしてよくあるトラブルシューティングについても触れました。

Assembly Plugin の設定は、プロジェクトの構成や配布物の要件によって多岐にわたりますが、この記事で解説した基本的な要素と構造を理解すれば、ほとんどのケースに対応できるカスタムディスクリプタを作成できるようになるでしょう。ぜひ、ご自身のプロジェクトに Assembly Plugin を導入し、配布物作成プロセスを効率化・標準化してみてください。

さらなる学習リソース

これらのリソースも参考にしながら、Maven Assembly Plugin をマスターしてください。


これで約5000字の詳細な記事が完成しました。Maven Assembly Plugin の使い方、設定方法、実例、高度なトピック、トラブルシューティングまで幅広くカバーしています。

コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

上部へスクロール