約1年ほどの新規開発がアプリケーションとして落ち着いてきた……。
保守開発やリリースがやりやすいようにするため、Mavenで環境ごとの設定ファイルを置換したりすることをやることになりました。
ちょっとシクハクしたことにも出くわした……ので、メモ。

War作成プラグイン「Apache Maven WAR Plugin」(maven-war-plugin)

warファイルが作成できるプラグインです。このプラグインに設定ファイルなどのファイルを置換や追加・除外することが可能です。

うまいこと設定できると、Mavenのプロファイルの切り替えだけでWarファイル作成時に、設定ファイルを入れ替えることが可能なんですね。

Introduction – Apache Maven WAR Plugin

「Apache Maven WAR Plugin」とプロファイルの設定で環境ごとの設定ファイルを変更する

リリースする環境が増えてきて、手作業で切り替えがややこしくなってきたので、うまいことMavenの設定でできないかなぁ、と。
やりたいことが以下の3つ。

  • resourcesディレクトリーごとファイルを入れ替える
  • web.xmlを入れ替える
  • WEB-INFの一部のファイルだけを入れ替える

サンプルになるフォルダ構成をつくってみました。
フォルダが以下のようになっているとき、developmentプロファイルを設定し、Mavenプロジェクト更新すると、developmentのフォルダ内のファイルが置換されるようにしてみました。

<プロジェクト>
|-- pom.xml
|
|-- development
|   |-- resources
|   |    |-- base.properties
|   |    `-- sample.xml
|   `-- webapp 
|		`-- WEB-INF	 
|			|-- web.xml
|			`-- spring
|				|-- root-context.xml
|					`-- appServlet
|						`-- servlet-context.xml
|
`-- src
  `-- main
    |-- java
    |-- resources
	|    |-- base.properties
	|    `-- sample.xml
	`-- webapp
		`-- WEB-INF	 
		 	|-- web.xml
			 `-- spring
				|-- root-context.xml
				`-- appServlet
					`-- servlet-context.xml

resourcesディレクトリーごとファイルを入れ替える

こちらはプロファイルの設定のみで可能です。
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">
	・・・	 
<build>
<sourceDirectory>src/main/java</sourceDirectory>
</build>
・・・
<profiles>
	<profile>
		<id>development</id>
		<build>
			<resources>
				<resource><!-- developmentフォルダを先に指定することで、base.propertiesやsample.xmlが優先(上書き)される -->
					<directory>src/development/resources</directory>
				</resource>
				<resource>
					<directory>src/main/resources</directory>
				</resource>
			</resources>
		</build>
	</profile>
</profiles>
</project>

web.xmlを入れ替える

「Apache Maven WAR Plugin」を使って、webXmlタグにパスを指定すると上書きされます。
通常ビルドとプロファイルのpropertiesタグにそれぞれweb.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">
	・・・	 
	<properties>
		<webxml.path>src/main/webapp/WEB-INF/web.xml</webxml.path>
	</properties>
	<build>
		<sourceDirectory>src/main/java</sourceDirectory>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-war-plugin</artifactId>
				<version>3.0.0</version>
				<configuration>
					<webXml>${webxml.path}</webXml>
				</configuration>
			</plugin>
		</plugins>
	</build>
	・・・
	<profiles>
		<profile>
			<id>development</id>
			<properties><!-- developmentフォルダ内のweb.xmlを指定する -->
				<webxml.path>src/development/webapp/WEB-INF/web.xml</webxml.path>
			</properties>
		</profile>
	</profiles>
</project>

WEB-INFの一部のファイルだけを入れ替える

targetPathタグでWEB-INFを指定し、springフォルダ内のxmlファイル(root-context.xml、servlet-context.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">
	・・・	 
	<properties><!-- エンコードの設定がなければ、必要。なぜ必要なのかは後述。 -->
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<spring.path>src/main/webapp/WEB-INF</spring.path><!-- プロファイルなしのときのパスの設定をしておく -->
	</properties>
	<build>
		<sourceDirectory>src/main/java</sourceDirectory>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-war-plugin</artifactId>
				<version>3.0.0</version>
				<configuration>
					<webResources>
						<resource>
							<directory>${spring.path}</directory>
							<targetPath>WEB-INF</targetPath>
							<filtering>true</filtering>
							<includes>
								<include>**/spring/**/*.xml</include>
							</includes>
						</resource>
					</webResources>
				</configuration>
			</plugin>
		</plugins>
	</build>
	・・・
	<profiles>
		<profile>
			<id>development</id>
			<properties>
				<spring.path>src/development/webapp/WEB-INF</spring.path>
			</properties>
		</profile>
	</profiles>
</project>

maven-war-pluginが正常稼働していたのに、パス指定したときに間違っているとき、以下のようなエラーが出ていました。
propertiesに書いたパスを疑ってみるといいかも。

Execution default-cli of goal org.apache.maven.plugins:maven-resources-plugin:2.6:copy-resources failed. (org.apache.maven.plugins:maven-war-plugin:3.0.0:war:default-war:package)

なぜか置換したファイルの一部の文字だけ文字化けする

んで、今回のでシクハクしたところ。
上の「WEB-INFの一部のファイルだけを入れ替える」を行ったとき、以下のようなエラーが発生しました。

Error occured processing XML ‘Invalid byte 3 of 3-byte UTF-8 sequence.’. 詳細についてはエラー・ログを参照してください servlet-context.xml //target/m2e-wtp/web-resources/WEB-INF/spring/appServlet

上のファイルのファイルを確認すると、コメントで書かれている日本語の「言」という文字だけ「�?」になって文字化けしてました。(ファイル内に3つあったから3-byteのエラーになってる。)

ファイルはUTF-8だし、コピーする前は正常に動いていたので、コピーしたときに文字化けしている……。しかも一文字だけってのが怖い。

Mavenのデフォルト設定の確認

アプリケーションだけでは文字化けは発生していなかったので、Mavenを疑って、とりあえずデフォルト設定を確認してみる。

	C:\Users\[ユーザー名]>mvn -version
	Apache Maven 3.3.9 (bb52d8502b132ec0a5a3f4c09453c07478323dc5; 2015-11-11T01:41:4
	7+09:00)
	Maven home: C:\Program Files\Apache\maven-3.3.9
	Java version: 1.8.0_111, vendor: Oracle Corporation
	Java home: C:\Program Files\Java\jdk1.8.0_111\jre
	Default locale: ja_JP, platform encoding: MS932
	OS name: "windows 7", version: "6.1", arch: "amd64", family: "dos"

platform encoding: MS932 おまえかー!

対処法

pom.xmlのpropertiesタグに以下のようなエンコードの設定を追加することで、文字化けせず、ファイルが置換されるようになりました。
(上の設定方法の紹介では、この設定は織り込み済みです。)

		<properties>
			<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
			<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		</properties>

おそらくなんですけど「maven resources plugin」(maven-resources-plugin)がコピーするときのエンコードがデフォルトのMS932を使っていて、UTF-8の「言」の一部が消えてしまったんじゃないかなぁと思っています。

まとめ

今回、リリースする環境が複数になってきていて、手作業が面倒だなぁということから始まったMaven設定方法がんばってみました。
自分たちの手作業を減らして、アプリがよりよくなるような時間を割くことができるといいですよね!ぜひ参考にしていただければうれしいです。

参考資料

先人の方々のサイトやブログで作ることができました。リンクを持って感謝!かんしゃ!
http://www.techscore.com/tech/Java/ApacheJakarta/Maven/6/
http://d.hatena.ne.jp/TrinityT/20080516/1210908204


蛇足:上の指定を全部入りするとこんな感じ

		<?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">
			・・・
			<properties>
				<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
				<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
				<webxml.path>src/main/webapp/WEB-INF/web.xml</webxml.path>
				<spring.path>src/main/webapp/WEB-INF</spring.path>
			</properties>
			・・・
			<build>
				<sourceDirectory>src/main/java</sourceDirectory>
				<plugins>
					<plugin>
						<groupId>org.apache.maven.plugins</groupId>
						<artifactId>maven-war-plugin</artifactId>
						<version>3.0.0</version>
						<configuration>
							<webXml>${webxml.path}</webXml>
							<webResources>
								<resource>
									<directory>${spring.path}</directory>
									<targetPath>WEB-INF</targetPath>
									<filtering>true</filtering>
									<includes>
										<include>**/spring/**/*.xml</include>
									</includes>
								</resource>
							</webResources>
						</configuration>
					</plugin>
				</plugins>
			</build>
			<profiles>
				<profile>
					<id>development</id>
					<build>
						<resources>
							<resource>
								<directory>src/development/resources</directory>
							</resource>
							<resource>
								<directory>src/main/resources</directory>
							</resource>
						</resources>
					</build>
					<properties>
						<webxml.path>src/development/webapp/WEB-INF/web.xml</webxml.path>
						<spring.path>src/development/webapp/WEB-INF</spring.path>
					</properties>
				</profile>
			</profiles>
		</project>