maven-assembly-plugin で実行可能な jar ファイルを作る
Java でバッチプログラムを作る際, class ファイルを jar にまとめてしまうことがよくあります.
しかし, 依存している外部の jar ファイルがある場合は, マニフェストファイルにクラスパスを書くか, --classpath などでクラスパスを指定しなくてはいけないため面倒です.
すべて jar ファイルに同梱してしまいたくなりますが, 外部 jar ファイルを一旦展開してから同梱しないと使えません.
こんな時に, maven-assembly-plugin を使うと便利です.
以下のような, pom.xml を用意します.
<?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/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>jp.example</groupId> <artifactId>example</artifactId> <packaging>jar</packaging> <name>Example Batch Application</name> <version>0.0.1-SNAPSHOT</version> <build> <sourceDirectory>src/main/java</sourceDirectory> <testSourceDirectory>src/test/java</testSourceDirectory> <outputDirectory>target/classes</outputDirectory> <testOutputDirectory>target/test-classes</testOutputDirectory> <defaultGoal>validate</defaultGoal> <resources> <resource> <directory>src/main/resources</directory> </resource> </resources> <testResources> <testResource> <directory>src/test/resources</directory> </testResource> </testResources> <pluginManagement> <plugins> <plugin> <artifactId>maven-jar-plugin</artifactId> <version>2.2</version> <configuration> <archive> <manifest> <mainClass>jp.example.command.Main</mainClass> </manifest> </archive> </configuration> </plugin> </plugins> </pluginManagement> <plugins> <plugin> <artifactId>maven-assembly-plugin</artifactId> <configuration> <descriptors> <descriptor>src/main/assembly/distribution.xml</descriptor> </descriptors> </configuration> </plugin> </plugins> </build> ... snip </project>
maven-jar-plugin の manifest 要素で, 実行するメインクラスを指定しています.
次に, src/main/assembly/distribution.xml を用意します.
<assembly> <id>distribution</id> <formats> <format>zip</format> </formats> <includeBaseDirectory>false</includeBaseDirectory> <dependencySets> <dependencySet> <unpack>true</unpack> <scope>runtime</scope> <outputDirectory>/</outputDirectory> </dependencySet> </dependencySets> </assembly>
format は zip にしないと, 自分自身で生成した artifact の jar ファイルをうまく同梱してくれないようです.
includeBaseDirectory を false にすることで, zip ファイルにベースディレクトリを含めなくなります.
dependencySet で unpack を true に, outputDirectory を "/" に指定すると, 依存関係にある外部 jar ファイルを展開し, zip ファイルに含めてくれます.
ここでは, dependency の scope = runtime の jar ファイルのみを同梱します.
Maven2 から assembly:assembly ターゲットを実行すると, 外部 jar ファイルを同梱した ZIP ファイルが生成されます.
$ mvn assembly:assembly ... snip [INFO] [assembly:assembly] [INFO] Reading assembly descriptor: src/main/assembly/distribution.xml [INFO] Processing DependencySet (output=/) [INFO] Building zip: /Users/nanasess/example/target/example-0.0.1-SNAPSHOT-distribution.zip [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESSFUL [INFO] ------------------------------------------------------------------------ [INFO] Total time: 18 seconds [INFO] Finished at: Mon Mar 30 23:32:28 JST 2009 [INFO] Final Memory: 37M/80M [INFO] ------------------------------------------------------------------------
jar も zip も拡張子が違うだけで中身は一緒なので, このままでも実行できてしまいます.
jar の方が良ければ rename してやれば良いと思います.
こんな感じで実行できます.
$ java -jar target/example-0.0.1-SNAPSHOT-distribution.zip Hello! World!
また, この方法を使うと "/META-INF/maven/groupId/artifactId/pom.properties" に artifactId, groupId, version が出力されます.
こんな感じのメソッドを作ると, コマンドラインからバージョン情報を出力したい時などに便利です.
/** * pom.properties の内容から {@link Properties} を取得する. * * @return pom.properties から取得した {@link Properties} */ private static Properties getPomProperties() { InputStream in = Main.class.getResourceAsStream("/META-INF/maven/groupId/artifactId/pom.properties"); Properties properties = new Properties(); try { if (in != null) { properties.load(in); } } catch (IOException e) { System.err.println(e.getMessage()); } return properties; } /** * pom.properties からバージョン情報を取得し, 標準出力へ書き込みます. */ private static void printVersion() { Properties properties = getPomProperties(); String msg = properties.getProperty("artifactId", "<unknown>"); String version = properties.getProperty("version", "<unknown version>"); System.out.println(msg + " \"" + version + "\""); System.out.println("Java version: " + System.getProperty("java.version", "<unknown java version>")); System.out.println("Java home: " + System.getProperty("java.home", "<unknown java home>")); System.out.println("Default locale: " + Locale.getDefault() + ", platform encoding: " + System.getProperty("file.encoding", "<unknown encoding>")); }
$ java -jar target/example-0.0.1-SNAPSHOT-distribution.zip --version example "0.0.1-SNAPSHOT" Java version: 1.6.0_07 Java home: /System/Library/Frameworks/JavaVM.framework/Versions/1.6.0/Home Default locale: ja_JP, platform encoding: SJIS