Documentation

You are viewing the documentation for the 2.2.0 release in the 2.2.x series of releases. The latest stable release series is 2.4.x.

§設定ファイルのシンタックスと機能

Play における設定ファイルは Typesafe config library をベースにしています。

Play アプリケーションのデフォルトの設定ファイルは、 conf/application.conf に保存されている必要があります。また、この設定ファイルは、 HOCON フォーマット ( “Human-Optimized Config Object Notation” ) で記述されています。

§代替設定ファイルの指定

システムプロパティを使うことで、異なる設定ソースの利用を強制することができます。

これらのシステムプロパティは application.conf の代替えとなる設定ファイルの指定に使います。代替えであって、追加ではないことに注意してください。ただし、代替えになる設定ファイルに include “application” と記述することで、デフォルトの設定ファイルを include することができます。さらに、 include 文の後で、任意の設定を上書きすることができます。

§Akka と一緒に使う

Akka 2.0 は Play アプリケーションと同じ設定ファイルを読み込みます。つまり、 Akka に関するあらゆる設定は application.conf で行うことができます。

§HOCON の文法

HOCON の文法は、ほとんど JSON にしたがって定義されています。JSON の仕様は http://json.org/ にあります。

§JSON と同じ部分

§コメント

//# から次の行まではコメントとして無視されます。ただし、//# が引用文字列のなかにある場合は含みません。

§root の括弧の省略

JSON ドキュメントは root として array や object を一つ持つ必要があります。空ファイルだったり、もしくは string などの array や object 以外しか含まないファイルは JSON ドキュメントとして正しくありません。

HOCON では、ファイルが中括弧や大括弧で始まっていない場合、中括弧 {} で囲まれているものとしてパースします。

しかし、始め中括弧 { を省略したにも関わらず 閉じ中括弧 } が存在するようなファイルは HOCON フォーマットとして正しくありません。中括弧はバランスされている必要があります。

§Key-value の区切り文字

JSON でキーと値を区切るために : が期待されるような箇所には、= を使うこともできます。

キーの直後に { が現れた場合、:= は省略可能です。つまり、 "foo" {}"foo" : {} と同じ意味です。

§カンマ

配列内の値や、オブジェクトのフィールドを区切るためのカンマは、1つ以上の改行(\n、10進数のASCIIコードでいえば 10)があれば省略可能です。

配列の最後の要素や、オブジェクトの最後のフィールドの後に、一つだけカンマを記述することができます。この余分なカンマは無視されます。

§重複したキー

JSON の仕様では、同じオブジェクトにおける重複したキーの取り扱いは定義されていません。 HOCON では、キーが重複していて、値の一方がオブジェクト以外の場合は、後に出現している方が先に出現しているものを上書きします。値が両方ともオブジェクトの場合は、二つのオブジェクトがマージされます。

Note: もしあなたが JSON においてキーが重複した場合に何らかの挙動を示すことを期待するのであれば、 HOCON は JSON の上位集合ではないといえます。ここでは、重複キーを含む JSON は正しくない、という仮定をしています。

オブジェクトのマージは次のように行われます。

キーに一旦オブジェクト以外の値をセットすることで、二つのオブジェクトをマージさせないことも可能です。これは、マージが常に二つの値に対して行われるからです。例えば、キーにオブジェクト、オブジェクト以外、オブジェクトの順に値をセットすると、まず非オブジェクトがオブジェクトを上書きします(常に非オブジェクトが優先されます)。次に、オブジェクトが非オブジェクトを上書きします(オブジェクトがそのキーに対する新しい値となります。マージはされません。)。したがって、1番目と3番目のオブジェクトがマージされることはありません。

以下の二つは同じです。

{
    "foo" : { "a" : 42 },
    "foo" : { "b" : 43 }
}

{
    "foo" : { "a" : 42, "b" : 43 }
}

以下の二つも同じです。

{
    "foo" : { "a" : 42 },
    "foo" : null,
    "foo" : { "b" : 43 }
}

{
    "foo" : { "b" : 43 }
}

ご覧のとおり、途中で "foo"null をセットすることで、オブジェクトのマージを行わないということが可能です。

§キーとしてのパス

もしキーが複数要素からなるパス式である場合、パスの最後以外の全ての要素が展開されて、オブジェクトが生成されます。パスの最後の要素は、値と組み合わされて、最も内側のオブジェクトのフィールドとなります。

言い換えると、

foo.bar : 42

は、

foo { bar : 42 }

と等しく、また、

foo.bar.baz : 42

は、

foo { bar { baz : 42 } }

と等しくなります。

また、これらの値は前述の方法でマージされます。つまり、

a.x : 42, a.y : 43

は、

a { x : 42, y : 43 }

と等しくなります。

パス式は値の結合と同じように扱われるため、キー中に空白を含めることができます。

a b c : 42

は、

"a b c" : 42

と等しくなります。

パス式は常に文字列に変換されるため、通常は文字列以外の型となるような単一の値さえも文字列になります。

特例として、引用符を含まない include は特別扱いされるため、キーにパス式を含んではいけません。

§置換

置換は、設定ツリーの別のパートを参照する機能です。

置換の文法は、 ${pathexpression} または $(?pathexpression} です。pathexpression は前述のパス式です。このパス式は、オブジェクトのキーに利用できるものと同じ文法です。

${?pathexpression} 中の ? はその直前に空白文字を含んではいけません。 ${? という3つの文字は、全くこのとおりにまとめて記述されている必要があります。

設定ツリー内に見つからない置換を行おうとした場合、設定ファイルの実装がシステム環境変数や他の外部ソースにある設定を参照して解決を試みます。 (環境変数に関する詳細は後のセクションでご説明します。)

引用文字列中では、置換はパースされません。置換を含むような文字列を取得したい場合、引用符で囲まれていない部分に置換を記述して、値の結合を行うとよいでしょう。

key : ${animal.favorite} is my favorite animal

もしくは、置換以外の部分を引用符で囲ってもよいでしょう。

key : ${animal.favorite}" is my favorite animal"

置換は設定ファイル中のパスを検索して解決されます。このとき、パスは root オブジェクトから始まります。言い換えれば、置換で指定するパスは 相対的 というより 絶対的 です。

置換処理は設定ファイルのパースにおける最終ステップで実行されます。したがって、置換は設定ファイルの前方で定義されたパスを参照することができます。もし、設定が複数のファイルから構成されているのであれば、置換が記述されているファイルとは別のファイルから値を取得することになるかもしれません。キーが複数回指定されている場合、一番最後にセットされた値(そのキーについてマージされたオブジェクトか、もしくは最後にセットされたオブジェクト以外の値)が置換により挿入されることになります。

設定によりある値に明示的に null がセットされた場合、その値を外部ソースから参照することはできなくなります。残念ながら、これを後の設定ファイルで “undo” する方法はありません。例えば、 root オブジェクトに { "HOME" : null } というフィールドを定義してしまうと、 ${HOME} という置換が外部ソースである環境変数を使って解決されることはありません。言い換えれば、 JavaScript の delete に相当するような操作は用意されていないということです。

もし、置換しようとしている値が設定や外部ソースに存在しない場合、 それは未定義として扱われます。${foo} という文法では未定義の置換は許されていないので、エラーとなります。

一方で、 ${?foo} という文法による置換が未定義となった場合、

置換はオブジェクトのフィールドの値や配列の要素(値の結合)においてのみ有効で、キーやその他の置換(パス式)内では利用できない。

置換は任意の値型(number、object、string、array、true、false、null)と置き換えることができます。置換が値の一部分でしかない場合は、型はそのまま維持されます。そうでなければ、値が結合されて string となります。

お互いに循環するような置換は不正であり、エラーとなります。

しかしながら、設定のパーサの実装において、オブジェクトが自身のパスを参照できることに十分注意しなければなりません。例えば、以下の設定は有効です。

bar : { foo : 42,
        baz : ${bar.foo}
      }

この設定における置換 ${bar.foo} を解決するにあたって bar の全ての置換を解決するようなパーサーを実装してしまったとすると、循環が発生します。実際には、このときに bar に再帰するのではなく、barfoo フィールドだけを解決するようなパーサーを実装しなければなりません。

§インクルード

§インクルードの文法

include 命令は、二重引用符に囲まれていない include という文字列と、その直後にある引用符に囲まれた文字列の二つの要素から構成されます。incude 命令はオブジェクトのフィールドの箇所に記述することができます。

引用符に囲まれていない include がパス式の始まり、つまりオブジェクトのキーが期待されるところに現れた場合、パス式やキーとしては解釈されません。

その代わりに、次の値は引用符で囲まれた文字列でなければなりません。その文字列は、インクルードされるファイル名かリソース名として解釈されます。

まとめると、引用符で囲まれていない include と引用符で囲まれた文字列は、文法的にはオブジェクトのフィールドに置換されます。また、その後に続けて他のフィールドや、さらなるインクルードをカンマ(前述のとおり、改行がある場合は省略可能)で区切って記述することができます。

引用符で囲まれていない include で始まるキーの後に、引用符で囲まれた文字列以外のものを続けて記述するのは間違いで、エラーとなります。

引用符で囲まれていない include と、引用符で囲まれた文字列の間は、任意の個数の空白文字または改行を含めることができます。

incude の引数に対しては、値の結合が機能しません。引数は必ず引用符で囲まれた文字列でなければなりません。置換は効かず、引数は引用符で囲まれていない文字列やその他の値も使うことはできません。

引用符で囲まれていない include は、パス式の始め以外の箇所に出現した場合は特別な意味を持ちません。

キーの後半に出現したり、

# this is valid
{ foo include : 42 }
# equivalent to
{ "foo include" : 42 }

オブジェクトや配列の値として出現することもあるでしょう。

{ foo : include } # value is the string "include"
[ include ]       # array of one string "include"

"include" という単語で始まるキーが必要な場合は、 "include" のように引用符をつけることができます。include が特別な意味を持つのは、引用符で囲まれていない時だけです。

{ "include" : 42 }

§インクルードの意味論: マージ

インクルードした側のファイル は include 命令と include 命令で指定された インクルードされたファイル の2要素から構成されています。(_インクルードされたファイル_ はファイルシステム上のファイルである必要はないのですが、今のところはそう思っておいてください)

インクルードされたファイル は配列ではなくオブジェクトを含んでいる必要があります。通常、JSON や HOCON がドキュメントの root として配列を許していることを考えると、 インクルードされたファイル の root にオブジェクトしか許されないのは特徴的です。

root として配列を持っているような include file は間違いで、エラーとなります。

インクルードされたファイル がパースされると、 root オブジェクトが生成されます。概念的には、root オブジェクトのキーが インクルードした側のファイル の include 命令と置換される、と考えてください。

§インクルードの意味論: 置換

インクルードされたファイル 内の置換は2ステップかけて、それぞれパスが異なる解釈をなされて解決されます。最初のステップでは、パスは インクルードされたファイル の root から相対的なものとして解釈されます。次のステップでは、パスは インクルードした側のファイル の root から相対的なものとして解釈されます。

前述のとおり、置換はパースの_後_、最終ステップで実行されます。置換は単一ファイルのファイルそれぞれについてではなく、アプリケーションの設定全体について行われます。

したがって、included file が置換を含む場合、パスはアプリケーションの設定の root から相対的なものとして「修正」されなければなりません。

例えば、次のような root 設定があるとします。

{ a : { include "foo.conf" } }

そして、次のような “foo.conf” があるとします。

{ x : 10, y : ${x} }

“foo.conf” を単体でパースしたとしたら、 ${x} はパス x の値 10 と評価されるはずです。しかし、 “foo.conf” を任意のオブジェクトのキー a にインクルードした場合、このパスは ${x} ではなく ${a.x} のように修正されなければなりません。

さらに、 root 設定で a.x が次のように再定義されているケースを考えてみます。

{
    a : { include "foo.conf" }
    a : { x : 42 }
}

このとき、 “foo.conf” の ${x}${a.x} に修正されて、 10 ではなく 42 と評価されます。置換は全ての設定のパース に処理されるからです。

一方で、 インクルードされたファイル から意図的にアプリケーションの root 設定を参照したいケースはよくあります。例えば、システムプロパティやリファレンス設定から値を取得するような場合です。前述のように「修正」されたパスを参照できるだけでは不十分で、今述べたように元々のパスも参照できる必要があるのです。

§インクルードの意味論: 存在しないファイル

インクルードされたファイル が存在しない場合、 include 命令は特にエラーもなく無視されます(インクルードされたファイル に空オブジェクトしか定義されていなかった場合と同じ挙動です)。

§インクルードの意味論: リソースの特定

概念的には、include 命令の引数となる引用符で囲まれた文字列は、その時パースされているファイルやその他のリソースと「隣接」していて、かつ同じ種類のリソースを識別するために使われます。この文字列や「隣接」の意味は、リソースの種類によって異なります。

設定のパーサーの実装によって、サポートしているリソースの種類に違いがある可能性があります。

Java Virtual Machine においては、 include 命令がインクルードされるものに「隣接」するリソースというものを見つけられなかった場合、パーサーの実装はクラスパス上に存在するリソースにフォールバックしてもよいことになっています。このルールのおかげで、ファイルシステムや URL 上の設定ファイルからクラスパス上のリソースを参照することができます。

Java のクラスパスにあるリソースについては、

ファイルシステム上のファイルについては、

URL については、

§期間指定用フォーマット

期間指定に利用する単位時間を表す文字列は、大文字・小文字の区別あり、かつ全ての小文字で記述されなければなりません。以下の文字列がサポートされています。

§サイズのバイト指定用フォーマット

バイトについては、以下の文字列がサポートされています。

10の累乗については、以下の文字列がサポートされています。

2の累乗については、以下の文字列がサポートされています。

§慣習としてのシステムプロパティによる上書き

アプリケーションの設定において、Java のシステムプロパティは設定ファイルに記述された設定を 上書き します。これにより、設定オプションをコマンドラインから指定することができます。