2009年12月30日水曜日

OValを使ったPageクラス(T2)でのバリデーション

スズキです。

T2の非同期通信(Ajax)までは形になったので、
http://blog.suz-lab.com/2009/12/query-t2ajax.html
次は、リクエストパラメータのバリデーションをどうするか?です。

今回は、バリデーションフレームワークとして、
OValを利用することにしました。
http://oval.sourceforge.net/

具体的には、""/mypage/index.json/insert"で処理されるメソッドを、
下記のようにしています。

--------【Java】--------
...
@Ajax
@POST
@ActionPath
public Navigation insert(
  @Form(resolverClass=OvalFormResolver.class) IndexJson.InsertForm form,
  ErrorInfo info
) {
  return (new JsonResponse<IndexJson.InsertForm, Map<String, String>>() {
    @Override
    protected Map<String, String> createResults() {
      Map<String, String> map = new HashMap<String, String>();
      map.put("url", this.getParams().getUrl());
      return map;
    }
  }).createResponse(form, info);
}

public static class InsertForm {
  private String url;
  public String getUrl() { return url; }
  public void setUrl(String url) { this.url = url; }
}
...
--------
http://code.google.com/p/suz-lab-gae/source/browse/trunk/suz-lab-feed/src/suz/lab/feed/page/other/mypage/IndexJson.java?r=77

ポイントは、
"@Form"、"resolverClass=OvalFormResolver.class"、"IndexJson.InsertForm"、"ErrorInfo"
の引数まわりです。

【@Form】
T2は"@Form"がついたPOJOに対して、リクエストパラメータをマッピングしてくれます。
OValはPOJOにアノテーションつけて、バリデーション処理するので、
ちょうどいいかなー、って感じです。

【resolverClass=OvalFormResolver.class】
で、マッピングするときに、POJOにつけたOValアノテーションで
バリデーションまでやっておきたいなーと思い、
実際にマッピングを行うクラス"OvalFormResolver"を作成し、
それを利用するように指定してます。(この辺は後で詳しく書きます)

【IndexJson.InsertForm】
リクエストパラメータがマッピングされるPOJOです。
OValのアノテーションを必要に応じて入れます。
いろいろ試しましたが、パブリックな静的インナークラスに落ち着きました。

【ErrorInfo】
マッピング時にエラーが発生した時のエラー情報が入っています。
"OvalFormResolver"で、Ovalバリデーション時のエラー情報も入るようにしています。

実際の"OvalFormResolver"は以下のようになっています。

--------【Java】--------
...
public class OvalFormResolver extends FormResolverImpl {
  @Override
  public void resolve(Form form, WebContext context, Object object,
ErrorInfo info) {
    super.resolve(form, context, object, info);
    Validator validator = new Validator();
    List<ConstraintViolation> violations = validator.validate(object);
    for(ConstraintViolation violation : violations) {
      info.addErrorInfo(violation.getMessage(), new
ConstraintsViolatedException(violation));
    }
  }
}
--------
http://code.google.com/p/suz-lab-gae/source/browse/trunk/suz-lab-gae/src/suz/lab/gae/t2/OvalFormResolver.java?r=71

上述したように、OValバリデーション処理して、エラーをErrorInfoに追加して
って処理になってます。

ここで、大問題が発生です。実際に実行すると、
resolverClass=OvalFormResolver.class
がききません...

ということで、下記の記事でも紹介している"Guice"の登場です。
http://blog.suz-lab.com/2009/12/mobylet-guice-t2-velocity-on-gaej.html

Guiceを利用することで、無事、"OvalFormResolver"が利用できるようになりました。
(実は長い道のりでした...)

ただ、一点、まだ何とかしたいことがあって、それは、
リクエストパラメータをマッピングするPOJOにgetter/setterを書かなければならないことです。

できれば、Seasar2のPublicフィールドのような感じで作れると嬉しいのですが...
(Seasar2のPropertyInterTypeみたいなことできないかなー?)

とりあえず、OValも、もっと何がどこまででいるか調査しないと...

【残タスク】
- API用のJSONフォーマット
- UserToolがおかしくなった
- cron/task処理結果ページのテンプレート
- Page関係の抽象クラス再考
--------
http://www.suz-lab.com

0 コメント: