読者です 読者をやめる 読者になる 読者になる

この日記は私的なものであり所属会社の見解とは無関係です。 GitHub: takahashikzn

Selecting First Match式の動作が仕様と異なる(ような気が)

OGNL

OGNLには、Selecting First Match式(以下、SFM式)というものがあります。

SFM式とは

これは、コレクションから指定した条件にマッチする最初の値を取得するために使用する式です。
要するに、みんな大好き内部イテレータのバリエーションの一つです。


例えば、こんな風にして使います。

{ 1, 2, 3 }.{^ (#this % 2 == 0) }

これは、数値リストの最初の偶数を返すSFM式です。

SFM式の評価結果が仕様通りでない(ような気が)

さて、先程のSFM式の評価結果は次の通りです。
(注: OGNL-2.7.3を使っています)

[2]

ん?なんか変ですね。

そうなんです。仕様によるとSFM式は最初にマッチした値を返すはずが、
なぜか最初にマッチした値だけを保持する、要素数1のリストを返してきます。


ちょっと仕様を確認してみましょう。

In order to get the first match from a list of matches, you could use indexing such as listeners.{? true }[0]. However, this is cumbersome because if the match does not return any results (or if the result list is empty) you will get an ArrayIndexOutOfBoundsException.


The selection syntax is also available to select only the first match and return it as a list. If the match does not succeed for any elements an empty list is the result.

objects.{^ #this instanceof String }


Will return the first element contained in objects that is an instance of the String class.




マッチした値のリストから最初のマッチ結果を取得するために、"listeners.{? true }[0]"のように書くことができる。
しかし、この書き方だともしマッチ結果が存在しなかったり0件だったりしたら、ArrayIndexOutOfBoundsExceptionになるだろう。


選択構文(*1)は最初のマッチ結果だけを取得するのにも使えるし、それをリストとして返却する。
もしマッチするものが一つもなければ空のリストを返す。


"object.{^ #this instanceof String }"はobjectsが保持している最初のStringクラスのインスタンスを返すだろう。



(*1) listener.{? ... } のこと


うーむ、マッチする最初のインスタンスを返すと書いてあるんだけどなぁ。

これでは結局、"objects.{^ #this instanceof String }[0]"と書かないとダメだし。
でもそれじゃSFM式の存在意義がないのでは…


一体なぜなんでしょう。OGNL-2.7.3を使っているからか?