| # OGNLガイド ## 目次 概要 リテラル 定義済みオブジェクト 変数 オブジェクトの生成 フィールドへのアクセス メソッドの呼び出し プロパティへのアクセス インデックスによるアクセス コレクションの操作 カンマ演算子とチェーン ## 概要 OGNL (Object Graph Navigation Language) は，Javaオブジェクトのプロパティにアクセスしたりメソッドを呼び出したりすることの出来る，Javaによく似た式言語です． Seasar2では，diconファイルの<property>要素の他，<component>要素・<initMethod>要素・<destroyMethod>要素・<arg>要素・<meta>要素にOGNL式を記述することが出来ます． OGNLの詳細はこちらを参照してください． ## リテラル ### Java標準のリテラル OGNLでは，Java言語で定められているリテラルをそのまま記述することが出来ます．
例 | 型
--- | ---
`true` | `boolean`
`false`
`10` | `int`
`0xABCD`
`100L` | `long`
`1.0` | `float`
`0.5F`
`0.01D` | `double`
`'A'` | `char`
`'\uFFFF'`
`"seasar2"` | `java.lang.String`
`null` | 参照型
文字列を記述する際には，ダブルクォーテーションが必要なことに注意してください．
    <component class="Person">
        <property name="name">"Taro Yamada"</property>
        <property name="age">25</property>
    </component>
### OGNL独自のリテラル OGNL独自のリテラルも用意されています． `java.math.BigDecimal`および`java.math.BigInteger`を表すリテラルがあります．
例 | 型
--- | ---
`100.00B` | `java.math.BigDecimal`
`100000H` | `java.math.BigInteger`
## 定義済みオブジェクト diconファイルに記述されたOGNL式は，S2コンテナが用意したコンテキストで実行されます． この実行コンテキストには，次のオブジェクトがあらかじめ定義されています．
名前 | 型 | 説明
--- | --- | ---
`container` | `org.seasar.framework.container.S2Container` | 現在のdiconファイルを処理しているS2コンテナです．
`request` | `javax.servlet.http.HttpServletRequest` | Webコンテナ上で実行されている場合，現在のスレッドで処理しているリクエストです． 設定されていない場合もあります．
`response` | `javax.servlet.http.HttpServletResponse` | Webコンテナ上で実行されている場合，現在のスレッドで処理しているレスポンスです． 設定されていない場合もあります．
`session` | `javax.servlet.http.session.HttpSession` | Webコンテナ上で実行されている場合，現在のスレッドで処理しているセッションです． 設定されていない場合もあります．
`servletContext` | `javax.servlet.ServletContext` | Webコンテナ上で実行されている場合，現在のS2コンテナに関連づけられたサーブレットコンテキストです． 設定されていない場合もあります．
さらに，コンテナに登録されているコンポーネントをその名前 (`name`属性の値) で参照することが出来ます． ## 変数 OGNLは変数を使うことが出来ます．全ての変数はグローバルで，先頭に'`#`'を付けます． 変数の設定はJava言語と同様，`=`演算子を使って値を代入しますが，diconファイルの中で変数を設定することはあまりないでしょう． ### 定義済みの変数
変数 | 説明
--- | ---
`#this` | この変数を含んだ式の「現在のオブジェクト」を表します．
`#self` | `<initMethod>`または`<destroyMethod>`のボディの中でのみ定義されている変数です． この変数は，現在のコンポーネント (`<initMethod>`または`<destroyMethod>`を囲む`<component>`要素で表されているオブジェクト) を参照します．
## オブジェクトの生成 オブジェクトを生成するには，Java言語の場合と同様に`new`演算子を使用します．クラス名はパッケージ名で修飾した完全限定名で指定する必要があります (`java.lang`パッケージの場合は省略することが出来ます)．
    <property name="url">new java.net.URL("http://localhost/")</property>
配列を生成することも出来ます．
    <property name="array1">new int[5]</property><!-- 配列の要素はすべて0 -->
    <property name="array2">new int[] {1, 3, 5}</property>
`java.uti.ArrayList`のインスタンスを手軽に生成することも出来ます．ただし，具体的な実装型 (`java.util.LinkedList`など) は指定することが出来ません．
    <property name="list">{"green", "red", "blue"}</property>
`java.util.Map`のインスタンスを手軽に生成することも出来ます．
    <property name="map">#{"key1" : "value1", "key2" : "value2", "key3" : "value3"}</property>
`java.util.Map`の実装型を指定することも出来ます (省略時は`java.util.LinkedHashMap`になります)．
    <property name="map">#@java.util.TreeMap@{"key1" : "value1", "key2" : "value2"}</property>
## フィールドへのアクセス オブジェクトの`public`なフィールドへアクセスすることが出来ます． ### インスタンスフィールド インスタンスフィールドは，Java言語と同じようにアクセスすることが出来ます．
    <property name="x">point.x</property>
### `static`フィールド `static`フィールドにアクセスするには，クラス名の前後を'@'で囲んで，その後にフィールド名を記述します．クラス名はパッケージ名で修飾した完全限定名を指定する必要があります (`java.lang`パッケージの場合は省略することが出来ます)．
    <property name="priority">@Thread@NORM_PRIORITY</property>
## メソッドの呼び出し オブジェクトの`public`なメソッドを呼び出すことが出来ます． ### インスタンスメソッド インスタンスメソッドは，Java言語と同じように呼び出すことが出来ます．
    <property name="files">dir.listFiles()</property>
### `static`メソッド `static`メソッドを呼び出すには，クラス名の前後を'@'で囲んで，その後にメソッド名を記述します．クラス名はパッケージ名で修飾した完全限定名を指定する必要があります (`java.lang`パッケージの場合は省略することが出来ます)．
    <property name="roots">@java.io.File@listRoots()</property>
## プロパティへのアクセス OGNLを使用する上で中心となるのがプロパティへのアクセスです． ### JavaBeansのプロパティ OGNLでは，JavaBeansにおけるプロパティ (getter/setterメソッドでアクセスできるもの)を扱うことが出来ます． 次の例では，`hello`という名前の付けられたコンポーネントの`message`というプロパティ値をコンポーネントとして定義しています．`message`プロパティの値は，`examples.dicon.HelloSetterInjection`クラスの`getMessage()`メソッドが返す値です．
    <component name="hello" class="examples.dicon.HelloSetterInjection">
        <property name="message">"Hello World!"</property>
    </component>

    <component name="msg">
        hello.message
    </component>
### Mapのエントリ `java.util.Map`のエントリもプロパティとして扱うことが出来ます．この場合，キーがプロパティ名となります．ただし，プロパティ名として使うことが出来るのは，識別子として有効な`java.lang.String`型のキーだけです． 次の例では，コンポーネント`one`はコンポーネント`map`のキー`one`に関連づけられている値`1B` (`java.math.BigDecimal`の1) になります．
    <component name="map">
        #{"one" : 1B, "two" : 2B, "three" : 3B}
    </component>

    <component name="one">
        map.one
    </component>
### コンポーネント コンテナに登録されているコンポーネントをプロパティとして扱うことが出来ます．この場合，コンポーネントの名前 (`name`属性の値) がプロパティ名となります．
    <component name="foo" class="Foo"/>

    <component name="">
        <property name="foo">container.foo</property>
    </component>
## インデックスによるアクセス ### Javaの配列 Javaの配列はJavaと同じようにアクセスすることが出来ます． 次の例では，`java.io.File#listRoots()`メソッドが返す配列の最初の要素がプロパティに設定されます．
    <property name="root">@java.io.File@listRoots()[0]</property>
### JavaBeansのインデックス付きプロパティ JavaBeansのインデックス付きプロパティを配列のように扱うことが出来ます． 次の例では，`org.seasar.framework.container.S2Container#getChild(int)`が呼び出されます．
    <property name="firstChild">container.child[0]</property>
### 連想配列 プロパティやフィールドを連想配列のようにアクセスすることが出来ます． 次の例では，`org.seasar.framework.container.S2Container#getNamespace()`が呼び出されます．
    <property name="tm">container["namepace"]</property>
### 連想配列によるインデックス付きプロパティ JavaBeansのインデックス付きプロパティの拡張として，任意の型をインデックスとするプロパティにアクセスすることが出来ます． 次の例では，`org.seasar.framework.container.S2Container#getComponentDef(String)`が呼び出されます．
    <property name="tm">container.componentDef["j2ee.transactionManager"]</property>
## コレクションの操作 ### `in` 演算子 `in`演算子を使うことで，配列またはコレクション (`java.util.Collection`のインスタンス) に要素が含まれているかをテストすることが出来ます． 次の例では，`color`というコンポーネントが`"red"`，`"green"`，`"blue"`の中に含まれているかをテストしています．`color`の値は`"red"`であるため，コンポーネント`contains`は`ture`になります (実際には`boolean`のラッパー型である`Boolean`型になります)．
    <component name="color">"red"</component>

    <component name="contains">color in {"red", "green", "blue"}</component>
### セレクション 配列またはコレクションから，条件にマッチする要素だけを選択することが出来ます． 次の例では，リスト`colors`から，3文字より長い要素だけを選択したリスト (要素は `"green"`と`"blue"`) がコンポーネント`selected`になります． `#this`は配列またはコレクションの各要素への参照です．
    <component name="colors">{"red", "green", "blue"}</component>

    <component name="selected">colors.{? #this.length() > 3}</component>
条件にマッチする最初の要素だけを選択することも出来ます． 次の例では，コンポーネント`firstMatch`は`"green"`になります．
    <component name="colors">{"red", "green", "blue"}</component>

    <component name="firstMatch">colors.{^ #this.length() > 3}</component>
条件にマッチする最後の要素だけを選択することも出来ます． 次の例では，コンポーネント`lastMatch`は`"blue"`を唯一の要素とするリストになります．
    <component name="colors">{"red", "green", "blue"}</component>

    <component name="lastMatch">colors.{$ #this.length() > 3}</component>
### プロジェクション 配列またはコレクションの各要素に対して，そのプロパティまたはメソッドを適用した戻り値からなるコレクションを作ることも出来ます． 次の例では，様々な型の数値からなるリスト`numbers`から，その文字列表現を要素とするリスト`strings`を作成しています．
    <component name="numbers">{0, 1L, 2.5f, 3B}</component>

    <component name="strings">numbers.{#this.toString()}</component>
## カンマ演算子とチェーン カンマ演算子を使うと，複数の副式を続けて記述することが出来ます．最後の副式の値が式全体の結果となります． 次の例では，標準出力へのプリントと，`foo`というオブジェクトの参照という二つの副式が記述されています．式全体の結果は最後の副式である`foo`になります．
    <property name="foo">@System@out.println("Foo:" + foo), foo</property>
同一オブジェクトに対するメソッドを繰り返し呼び出す場合などに便利な記述方法が用意されています． 次の例では，`<initMethod>`要素の中で`#self` (`HashSet`のインスタンス) に対する`add()`メソッドの呼び出しを3回繰り返しています．`add()`メソッドは，それを囲んでいるカッコで区切られたコンテキストで評価されます．このコンテキストは`#self` (`HashSet`)であるため，どの`add()`メソッドの呼び出しも`HashSet`に対して行われます．
    <component name="set" class="java.util.HashSet">
        <initMethod>#self.( add("one"), add("two"), add("three") )</initMethod>
    </component>
| © Copyright The Seasar Foundation and the others 2004-2005, all rights reserved.