改めて Cubby のライフサイクルを調べた
Cubby でちょっとした Web アプリケーションを作ったのですが、意外と分かっていないところがあったのでロガーを差し込みまくっていろいろ調べました。
アクションクラスの各メソッドの実行順序
アクションメソッド(戻り値の型が org.seasar.cubby.action.ActionResult のメソッド)、initialize、prerender、postrender、そして JSP(View 層)、それぞれどのような順番で実行されているかといいますと、以下の順番です。
- initialize
- アクションメソッド
- prerender
- JSP
- postrender
バリデータがあれば、以下のようになります。
- initialize
- バリデータ
- アクションメソッド
- prerender
- JSP
- postrender
では、バリデータでエラーとなった場合はどうなるかというと以下のようになります。アクションメソッドだけが実行されません。
パラメータにバインディングされるタイミング
リクエストパラメータは、いつアクションクラスの属性にバインディングされるのでしょうか。ここでいうバリデータは公式サイトで「ユーザー作成のロジックによるバリデーション」として説明されているものとします。以下のように initialize のときのみ null(バインドされていない)でした。
- ×initialize
- ○バリデータ
- ○アクションメソッド
- ○prerender
- ○JSP
- ○postrender
次にバリデーションでエラーが発生した場合です。これはアクションメソッドが実行されないだけでした。
- ×initialize
- ○バリデータ
- ○prerender
- ○JSP
- ○postrender
ここで気をつけたいのは、バリデータでいくらチェックしてエラーを出してもバインディングは行われてしまうので、prerender や JSP、postrender でバインディングされたアクションクラスの属性値を使うときは十分に気をつけなければならないということです。これで私は危ういプログラムを作るところでした。バリデータはあくまで「危ういデータをアクションクラスに渡さない」ための仕組みであって、「危ういデータをバインディングさせない」仕組みではないということですね。
バリデータの実行順序
DefaultValidationRules のサブクラスを使って以下の順番で add されていたとします。
- リクエストパラメータ arg1 のバリデータ
- DATA_TYPE のユーザー作成のロジックによるバリデータ
- DATA_CONSTRAINT のユーザー作成のロジックによるバリデータ
- リクエストパラメータ arg2 のバリデータ
実行順序はもちろん以下のようになります。
- 1.リクエストパラメータ arg1 のバリデータ
- 2.DATA_TYPE のユーザー作成のロジックによるバリデータ
- 4.リクエストパラメータ arg2 のバリデータ
- 3.DATA_CONSTRAINT のユーザー作成のロジックによるバリデータ
ここで「1.リクエストパラメータ arg1 のバリデータ」がエラーと判定したらどうなるでしょうか。以下のようになります。
つまり、DATA_CONSTRAINT のユーザー作成のロジックによるバリデータが実行されないわけですね。では、「2.DATA_TYPE のユーザー作成のロジックによるバリデータ」がエラーと判定したらどうなるでしょうか。
これは、2つのパターンがあります。まずは、公式サイトに書いてあるとおりに ValidationException をスローした場合。
- 1.リクエストパラメータ arg1 のバリデータ
- 2.DATA_TYPE のユーザー作成のロジックによるバリデータ
エラーと判定したバリデータでバリデーション・フェーズが終わってしまいます。
公式サイトには書いていないですが、apply メソッドの引数である ActionErrors のオブジェクトにエラーメッセージを詰め込んだ場合は以下のようになります(当初、この方法がわからなくて悩みました)。
こうやって(自分で実験しながら)まとめてみると、JSF なんかに比べたら実に単純で簡単なんだと思うのですが、単純が故にハマることもあるんですよね。