Javaのpropertyファイルと環境

propertyファイルには、環境に合わせて変わる値を設定する。
開発環境、検証環境、商用環境の3通りの環境があって、Antでビルドするときに環境にあった値が設定されるようにする方法は3通りほどある。

  1. 各環境用のpropertyファイルを用意して、copyタスクで対象の環境用のファイルをコピーする。
  2. 環境に合わせて変わる部分を変数にし、replaceタスクで変換する。
  3. 環境に合わせて変わる部分をreplaceregexpタスクによって正規表現で置換する。

各方法で共通の部分

各方法の説明に移る前に、各方法で共通の部分があるため先に記載する。

<target name="checktarget">
    <fail message="target property is invalid:${target} ${line.separator}set the parameter product|staging|dev${line.separator}ex) ant -Dtarget=product deploy">
        <condition>
            <not>
                <or>
                    <equals arg1="${target}" arg2="product" />
                    <equals arg1="${target}" arg2="staging" />
                    <equals arg1="${target}" arg2="dev" />
                </or>
            </not>
        </condition>
    </fail>

    <condition property="env.product" value="true">
        <equals arg1="${target}" arg2="product" />
    </condition>
    <condition property="env.staging" value="true">
        <equals arg1="${target}" arg2="staging" />
    </condition>
    <condition property="env.dev" value="true">
        <equals arg1="${target}" arg2="dev" />
    </condition>
</target>

方法1

各環境用のpropertyファイルを用意して、copyタスクで対象の環境用のファイルをコピーする。

<target name="src-compile" description="ソースファイルをコンパイルします">
    <copy todir="${work.dir}" overwrite="yes">
        <fileset dir="EnvironmentFile/${target}">
            <include name="**" />
            <exclude name="_*/**" />
        </fileset>
    </copy>
    
    <javac 略>
    </javac>
</target>

ディレクトリ構成は以下の通りとし、ant -Dtarget=stagingのように実行する。EnvironmentFile直下のディレクトリ名をtargetプロパティと併せている。
-Dtarget:
-Dプロパティ名でプロパティーを定義する。<property name="プロパティ名" value="値"/>と同等。

/EnvironmentFile/dev/system.properties
/EnvironmentFile/staging/system.properties
/EnvironmentFile/product/system.properties

一番シンプルだが、プロパティファイルに変更があるたびに、環境分のファイルを修正しなければならず非効率。

方法2

環境に合わせて変わる部分を変数にし、replaceタスクで変換する。

<target name="dev-environment" if="env.dev">
    <property name="db.pass" value="devPass" />
</target>
<target name="staging-environment" if="env.staging">
    <property name="db.pass" value="stagingPass" />
</target>
<target name="production-environment" if="env.product">
    <property name="db.pass" value="productPass" />
</target>

<target name="src-compile" description="ソースファイルをコンパイルします">
    <replace file="${work.dir}/system.properties" token="@db-pass@" value="${db.pass}" encoding="UTF-8" />
    
    <javac 略>
    </javac>
</target>

@変数名@のような命名ルールを策定する。replaceタスクのtokenに変数を設定して以下のsystem.propertiesファイルを置換する。

dbPass=@db-pass@

この方式だと、プロパティファイルはどれだけ環境が増えても1つで済む。設定値が変わっても修正するファイルはbuild.xmlのみ。
しかしプロパティファイルに設定されているのが変数なので、自PCでEclipseから実行したいときなど、値に実際の開発環境の値ではなく変数名が設定されてしまう。

3つの方法で1と2の欠点を解消する。

方法3

環境に合わせて変わる部分をreplaceregexpタスクによって正規表現で置換する。

2のreplaceタスクを以下の通りreplaceregexpタスクに変更する。

<replaceregexp file="${work.dir}/system.properties" match="(dbPass=).*" byline="true" replace="\1${db.pass}" encoding="UTF-8" />

(dbPass=)dbPass=をグループ化してreplace部で後方参照できるようにし、実際の値部分は${db.pass}で置換する。

system.propertiesファイルは毎回置換されるので、実際の開発環境の値を自PCのファイルに書いて問題ない。

dbPass=devPass

replaceregexpのオプションはantのJavadocを参照のこと。

Attribute Description Required
file file for which the regular expression should be replaced. Yes if no nested <fileset> is used
match The regular expression pattern to match in the file(s) Yes, if no nested <regexp> is used
replace The substitution pattern to place in the file(s) in place of the regular expression. Yes, if no nested <substitution> is used
flags The flags to use when matching the regular expression. For more information, consult the Perl5 syntax
g : Global replacement. Replace all occurrences found
i : Case Insensitive. Do not consider case in the match
m : Multiline. Treat the string as multiple lines of input, using "^" and "$" as the start or end of any line, respectively, rather than start or end of string.
s : Singleline. Treat the string as a single line of input, using "." to match any character, including a newline, which normally, it would not match.
No
byline Process the file(s) one line at a time, executing the replacement on one line at a time (true/false). This is useful if you want to only replace the first occurrence of a regular expression on each line, which is not easy to do when processing the file as a whole.
Defaults to false.
No
encoding The encoding of the file. since Apache Ant 1.6 No - defaults to default JVM encoding
preserveLastModified Keep the file timestamp(s) even if the file(s) is(are) modified. since Ant 1.8.0. No, defaults to false