改めて Cubby のライフサイクルを調べた

 Cubby でちょっとした Web アプリケーションを作ったのですが、意外と分かっていないところがあったのでロガーを差し込みまくっていろいろ調べました。

アクションクラスの各メソッドの実行順序

アクションメソッド(戻り値の型が org.seasar.cubby.action.ActionResult のメソッド)、initialize、prerender、postrender、そして JSP(View 層)、それぞれどのような順番で実行されているかといいますと、以下の順番です。

  1. initialize
  2. アクションメソッド
  3. prerender
  4. JSP
  5. postrender

バリデータがあれば、以下のようになります。

  1. initialize
  2. バリデータ
  3. アクションメソッド
  4. prerender
  5. JSP
  6. postrender

では、バリデータでエラーとなった場合はどうなるかというと以下のようになります。アクションメソッドだけが実行されません。

  1. initialize
  2. バリデータ
  3. prerender
  4. JSP(Validation アノテーションの errorPage で指定したもの)
  5. postrender

パラメータにバインディングされるタイミング

 リクエストパラメータは、いつアクションクラスの属性にバインディングされるのでしょうか。ここでいうバリデータは公式サイトで「ユーザー作成のロジックによるバリデーション」として説明されているものとします。以下のように initialize のときのみ null(バインドされていない)でした。

  1. ×initialize
  2. ○バリデータ
  3. ○アクションメソッド
  4. ○prerender
  5. JSP
  6. ○postrender

 次にバリデーションでエラーが発生した場合です。これはアクションメソッドが実行されないだけでした。

  1. ×initialize
  2. ○バリデータ
  3. ○prerender
  4. JSP
  5. ○postrender

ここで気をつけたいのは、バリデータでいくらチェックしてエラーを出してもバインディングは行われてしまうので、prerender や JSP、postrender でバインディングされたアクションクラスの属性値を使うときは十分に気をつけなければならないということです。これで私は危ういプログラムを作るところでした。バリデータはあくまで「危ういデータをアクションクラスに渡さない」ための仕組みであって、「危ういデータをバインディングさせない」仕組みではないということですね。

バリデータの実行順序

 DefaultValidationRules のサブクラスを使って以下の順番で add されていたとします。

  1. リクエストパラメータ arg1 のバリデータ
  2. DATA_TYPE のユーザー作成のロジックによるバリデータ
  3. DATA_CONSTRAINT のユーザー作成のロジックによるバリデータ
  4. リクエストパラメータ arg2 のバリデータ

 実行順序はもちろん以下のようになります。

  1. 1.リクエストパラメータ arg1 のバリデータ
  2. 2.DATA_TYPE のユーザー作成のロジックによるバリデータ
  3. 4.リクエストパラメータ arg2 のバリデータ
  4. 3.DATA_CONSTRAINT のユーザー作成のロジックによるバリデータ

 ここで「1.リクエストパラメータ arg1 のバリデータ」がエラーと判定したらどうなるでしょうか。以下のようになります。

  1. 1.リクエストパラメータ arg1 のバリデータ
  2. 2.DATA_TYPE のユーザー作成のロジックによるバリデータ
  3. 4.リクエストパラメータ arg2 のバリデータ

 つまり、DATA_CONSTRAINT のユーザー作成のロジックによるバリデータが実行されないわけですね。では、「2.DATA_TYPE のユーザー作成のロジックによるバリデータ」がエラーと判定したらどうなるでしょうか。

 これは、2つのパターンがあります。まずは、公式サイトに書いてあるとおりに ValidationException をスローした場合。

  1. 1.リクエストパラメータ arg1 のバリデータ
  2. 2.DATA_TYPE のユーザー作成のロジックによるバリデータ

エラーと判定したバリデータでバリデーション・フェーズが終わってしまいます。

 公式サイトには書いていないですが、apply メソッドの引数である ActionErrors のオブジェクトにエラーメッセージを詰め込んだ場合は以下のようになります(当初、この方法がわからなくて悩みました)。

  1. 1.リクエストパラメータ arg1 のバリデータ
  2. 2.DATA_TYPE のユーザー作成のロジックによるバリデータ
  3. 4.リクエストパラメータ arg2 のバリデータ


 こうやって(自分で実験しながら)まとめてみると、JSF なんかに比べたら実に単純で簡単なんだと思うのですが、単純が故にハマることもあるんですよね。