- PR -

JSFのvalidatorで複数フィールドの関係を検査する方法

1
投稿者投稿内容
TAKEZO
ベテラン
会議室デビュー日: 2003/12/25
投稿数: 59
投稿日時: 2006-06-22 16:13
JSFのValidatorインターフェース、もしくはメソッドは FacesContext,UIComponent,Object
の引数をとり、妥当性検査の対象フィールドが1つで有れば特に問題は無いと思うのですが
例えばフィールドAとフィールドBの入力値が等しいか、など複数フィールドの関係について
入力チェックをする際には下記のようなコードを記述するのしかないのでしょうか?

Map params = context.getExternalContext().getRequestParameterMap();
String fieldA = params.get("main:form:fieldA");
String fieldB = params.get("main:form:fieldB");

この様な書き方をした場合、GUIの構成を少し変更しただけでID名が代わってしまい、該当箇所
も合わせて修正する必要がありスマートな方法ではない気がします。皆さんはどのような実装を
されておりますでしょうか?
uk
ぬし
会議室デビュー日: 2003/05/20
投稿数: 1155
お住まい・勤務地: 東京都
投稿日時: 2006-06-22 17:11
パッと思いつく方法ですが、カスタムバリデータを作成し、その属性として比較相手の
フィールドIDを渡すようにすれば、汎用的なバリデーションができるのではないでしょうか。
TAKEZO
ベテラン
会議室デビュー日: 2003/12/25
投稿数: 59
投稿日時: 2006-06-22 17:39
ukさんありがとうございます。確かにカスタムバリデータを作成すれば引数を渡す事が
出来るので、ビューの編集時に合わせて直してしまえばメンテナンスが簡単になりそう
ですね。

現在作成しているアプリでは、MyFacesとSpringを連携して使っている関係で
バリデータメソッドを使っています(ロジックインスタンスをマネージドビーンに注入し
バリデータの中でそのロジックインスタンスを利用している関係で)。

カスタムバリデータにも依存オブジェクトの注入が出来ればベストなんですが、現時点
ではマネージドビーンにしか出来ないようで、微妙に不便です。
TAKEZO
ベテラン
会議室デビュー日: 2003/12/25
投稿数: 59
投稿日時: 2006-06-22 17:59


[ メッセージ編集済み 編集者: TAKEZO 編集日時 2006-06-22 18:00 ]
よしだひろゆき
大ベテラン
会議室デビュー日: 2004/11/22
投稿数: 141
投稿日時: 2006-06-22 18:58
いくつかコメントがあります。

(1)validatorは単項目チェックが基本でしょう。
項目間の相関チェックは想定外ではないでしょうか?
相関チェックは、ボタンのアクションで実行するのが普通なのかもしれません。

(2)validatorの中で他のフィールドへアクセスする方法
他のフィールドの値を取るのに、パラメタから取り出すのはレンダラーの独立性を
損ねるので、あまりよろしくありません。
UIComponent.findComponentを使うのが普通かと思います。
もちろんフィールドIDをハードコーディングする問題は回避できませんが。

(3)validatorに値を与える方法
カスタムバリデータを作るのがベストですが、とりあえずの策としては以下の方法があります。
まず、JSPの方はこんな感じ:
<h:inputText ...>
<f:validator validatorId="MyValidator"/>
<f:attribute name="valparam" value="...."/>
</h:inputText>

f:validatorとf:attributeを並べます。

次に、バリデータの方のコーディングはこんな感じ:
public void validate(FacesContext ctx, UIComponent comp, Object value)
throws ValidatorException {
String valparam = (String) comp.getAttribute().get("valparam");
...
}

バリデータの対象コンポーネントの汎用属性を使うわけです。
(「よくわかるJavaServer Facesのしくみ」3.5節参照)
JSPが書き方がちょっと普通じゃないので、何度もこういうコーディングが必要ならば
やはり引数を取れるカスタムバリデータを開発すべきだろうと思います。
TAKEZO
ベテラン
会議室デビュー日: 2003/12/25
投稿数: 59
投稿日時: 2006-06-23 10:54
よしだ様いつもありがとうございます。下記内容についてですが、、、

引用:

よしだひろゆきさんの書き込み (2006-06-22 18:58) より:

(2)validatorの中で他のフィールドへアクセスする方法
他のフィールドの値を取るのに、パラメタから取り出すのはレンダラーの独立性を
損ねるので、あまりよろしくありません。
UIComponent.findComponentを使うのが普通かと思います。
もちろんフィールドIDをハードコーディングする問題は回避できませんが。



UIComponent経由で入力値にアクセスした場合、思うような結果が取得できなかったため
パラメータを直接利用するに至りました。フィールドAの妥当性検査後フィールドBで
フィールドAとフィールドBの相関チェックを行っています。マネージドビーンのスコープ
はリクエストになっています。

1.フィールドAが妥当だった場合、バリデーションフェーズで
 fieldA.getSubmittedValue は null
 fieldA.getLocalValue は 入力値

2.フィールドAが不正だった場合、バリデーションフェーズで
 fieldA.getSubmittedValue は 入力値
 fieldA.getLocalValue は null

従って、フィールドBのバリデーションフェーズでフィールドAの値を取得するには
fieldA.getLocalValue、fieldA.getSubmittedValueの優先順位で値を取得すれば
フィールドBのバリデーションが行えます。
(fieldA.getSubmittedValueがnullの時点でフィールドBのバリデーションを終了
しても良いと思いますが)

ところが

3.1回目フィールドAが妥当で、他のフィールドが不正。
 2回目フィールドAが不正だった場合 
 fieldA.getSubmittedValue は 入力値
 fieldA.getLocalValue は 1回目妥当と判断された入力値

というようになり、必ずしもfieldA.getLocalValueを優先すれば良いとも
限らなくなります。
===================================

と、ここまで書いて気づいたのですがisValidで今回のバリデーションでフィールドAが
妥当だったか判断すれば良さげでした。一応、ここまで書いたので他の方の参考までに
書き込みしておきます。

但し、画面の並びで呼び出されるバリデーションの順番が変わるか分かりませんが
isValidがバリデーションの結果falseなのか、まだ行われていない為falseなのかが
区別出来ない気がしますね。呼びだし順は確認した上で使わないと予期しない動きを
しそうです。。。。


[ メッセージ編集済み 編集者: TAKEZO 編集日時 2006-06-23 11:04 ]
よしだひろゆき
大ベテラン
会議室デビュー日: 2004/11/22
投稿数: 141
投稿日時: 2006-06-23 14:36
なるほど、確かに入力フィールドの評価順によって状況が変わりますね。

引用:

従って、フィールドBのバリデーションフェーズでフィールドAの値を取得するには
fieldA.getLocalValue、fieldA.getSubmittedValueの優先順位で値を取得すれば
フィールドBのバリデーションが行えます。


逆ではないでしょうか? getSubmittedValueに値があればそれは必ず入力値です。
空入力の場合は空文字列が入ります。
だから、getSubmittedValueがnullの時にgetLocalValueを見ればよいのではないでしょうか?

ただ、getSubmittedValueがnullの時、必ずgetLocalValueがそのときの入力値かというと、厳密にはそうではなくて、以下の二つの条件が成り立つときに限って、前回の入力値になっていることがあると思います。
(1)入力頁にformが二つ以上あって、当該の入力フィールドを含まない方のformをsubmitした、かつ
(2)前回この入力フィールドは妥当でlocalValueに移されたが、他の入力が不正だったため、バッキングビーンへは移されなかった。

ちなみにUIInputのソースを見ると、validフラグはdecodeの最初で強制的にtrueにし、エラーを見つけたときにfalseにセットしています。

ですから、上記の(1)(2)が成り立つ場合には、isValueもtrueなので区別できませんね。
まぁ、(1)のような頁を作ることは滅多に無いとは思いますが。

いずれにしても、Process Validationフェーズで他のフィールドを参照することは、JSFの設計上は想定外なのかなと思います。
1

スキルアップ/キャリアアップ(JOB@IT)