理系学生日記

おまえはいつまで学生気分なのか

Maven管理下のリソースファイルの値を実行時にプロパティの値で置換する (Resource Filtering)

ここ半年くらいジャバジャバしていて、maven とかの実力不足を痛感している今日このごろで、勉強しているといろいろなことができるんだなぁというのを発見したりします。 一例として Maven には、動的にリソースの特定の値を置き換える機構が存在していて、これを Resource Filtering といいます。

たとえば、src/main/resources/test.properties をこんな風に書いておいて、

test.prop=${environment.name}

pom.xml でフィルタリングを有効化する。

<project>
  (snip)
  <build>
    <resources>
      <resource>
        <directory>src/main/resources</directory>
        <filtering>true</filtering>
      </resource>
    </resources>
  </build>
</project>

この状態で、resources:resources ゴールを実行すると、生成される test.properties${environment.name}hello world に置換されます。

$ mvn resources:resources -Denvironment.name='hello world'
$ cat target/classes/test.properties
test.prop=hello world

基本的な使い方

上では、resources:resources ゴールを実行するときに、直接値を渡しましたが、当然これは pom.xml 内のプロパティとして定義しても良いです。というか、コマンドラインで直接指定することの方がレアでしょう。 また、実行時に置換させる必要があるということは、実行時まで値が確定できないということなので、よくあるパターンとしては profile 毎に値を指定するケースの方が多いと思います。

以下のように profile の中にプロパティを定義しておいて…

<project>
    (snip)
    <profiles>
        <profile>
            <id>production</id>
            <properties>
                <environment.name>product</environment.name>
            </properties>
        </profile>
        <profile>
            <id>development</id>
            <properties>
                <environment.name>dev</environment.name>
            </properties>
        </profile>
    </profiles>
</project>

あとは profile を指定して resources:resources を実行すれば、当該プロファイルで定義した値で置換されます。

$ mvn resources:resources -P production
$ cat target/classes/test.properties
test.prop=product

pom.xml をきれいに

ただ、こんなことを大量にしていたら、ただでさえ読みづらくなる profiles まわりがさらに長くなってよくわからなくなる。そういう場合は filters 要素を使って、置き換え対象のプロパティを別ファイルに切り出せば良いです。 profile には、filter 要素で置き換えるプロパティを定義したプロパティファイルを定義しておきます。

<project>
    (snip)
    <profiles>
        <profile>
            <id>production</id>
            <build>
                <filters>
                    <filter>src/main/resources/production.properties</filter>
                </filters>
            </build>
        </profile>
        (snip)
    </profiles>
</project>
$ cat src/main/resources/production.properties
environment.name=productA$ 
$ mvn resources:resources -P production
$ cat target/classes/test.properties
test.prop=productA%