SAStrutsで独自の検証用アノテーションを作成する

SAStrutsで既に@Requiredなどいくつかの検証用アノテーションが利用できます。
そこで、それらとは別に独自の検証用アノテーションを作成しようと思ったのですが、
私の探し方が悪いのかSAStrutsのドキュメントなどには記述が見つかりませんでした。
仕方が無いので、SAStrutsソースコードを追いながら、作成してみたいと思います。

SAStrutsのドキュメント内に記述がありました。以下のリンクの最後のほうを参照です。
id:higayasuo さん、ありがとうございます。
http://sastruts.seasar.org/featureReference.html#Validator

検証用アノテーションクラスを作成する

今回は、郵便番号を検証するアノテーションを作成します。
@Maskを利用すれば実現できますが、まあサンプルということで…

Zip.java
package takehiro.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.seasar.struts.annotation.Arg;
import org.seasar.struts.annotation.Msg;
import org.seasar.struts.annotation.Validator;

/**
 * 郵便番号かどうかを検証するためのアノテーションです。
 * 
 * @author takehiro
 *
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@Validator("zip")
public @interface Zip {

    /**
     * メッセージです。
     * 
     */
    Msg msg() default @Msg(key = "errors.zip");

    /**
     * メッセージの最初の引数です。
     * 
     */
    Arg arg0() default @Arg(key = "");

    /**
     * 検証の対象となるメソッド名を指定します。 複数ある場合はカンマで区切ります。
     * 
     */
    String target() default "";
}

@Validator("zip") を指定するのがミソです。引数に指定した "zip" が
このアノテーションを指すキーになります。

検証用メソッドを作成する

次は、実際に郵便番号を検証するメソッドを作成します。
org.seasar.struts.validator.S2FieldChecks を継承して新しいクラスを作成しました。

CustomizedS2FieldChecks.java
package takehiro.validator;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.validator.Field;
import org.apache.commons.validator.GenericValidator;
import org.apache.commons.validator.Validator;
import org.apache.commons.validator.ValidatorAction;
import org.apache.struts.action.ActionMessages;
import org.seasar.struts.validator.S2FieldChecks;

/**
 * Seasar2用の独自検証メソッドです。
 * 
 * @author takehiro
 *
 */
public class CustomizedS2FieldChecks extends S2FieldChecks {

    private static final long serialVersionUID = 1L;

    /**
     * 郵便番号かどうかをチェックします。
     * 
     * @param bean
     *            JavaBeans
     * @param validatorAction
     *            バリデータアクション
     * @param field
     *            フィールド定義
     * @param errors
     *            エラーメッセージの入れ物
     * @param validator
     *            バリデータ
     * @param request
     *            リクエスト
     * @return 検証結果がOKかどうか
     */
    public static boolean validateZip(Object bean,
            ValidatorAction validatorAction, Field field,
            ActionMessages errors, Validator validator,
            HttpServletRequest request) {
        String value = getValueAsString(bean, field);
        if (!GenericValidator.isBlankOrNull(value)) {
            final Pattern zipPattern = Pattern.compile("\\d{3}-\\d{4}");
            final Matcher matcher = zipPattern.matcher(value);
            if (!matcher.matches()) {
                addError(errors, field, validator, validatorAction, request);
                return false;
            }
        }
        return true;
    }
}

検証用メソッドを登録する

先ほど作成した検証用のメソッドを登録します。
具体的には、validator-rules.xml に登録することになります。
ここで、name属性の "zip" は、アノテーションクラスの@Validatorの引数と同じにします。
また、msg属性の "errors.zip" は、次に追加するエラーメッセージのキーとなります。

validator-rules.xml
…中略

     <validator name="zip"
            classname="takehiro.validator.CustomizedS2FieldChecks"
               method="validateZip"
         methodParams="java.lang.Object,
                       org.apache.commons.validator.ValidatorAction,
                       org.apache.commons.validator.Field,
                       org.apache.struts.action.ActionMessages,
                       org.apache.commons.validator.Validator,
                       javax.servlet.http.HttpServletRequest"
              depends=""
                  msg="errors.zip"/>

…中略

エラーメッセージを追加する

郵便番号の検証でエラーが発生した場合に表示するエラーメッセージを追加します。
先ほど書いたように、キー "errors.zip" は、validator-rules.xml の msg 属性と一致させます。

application_ja.properties
errors.zip={0}は郵便番号として不正です。
application.properties
errors.zip={0} is an invalid zip code.

Actionのpublicフィールドに、作成したアノテーションを追加する

今回は、SAStrutsチュートリアルに含まれる ValidatorAction を利用します。
以下のように、郵便番号を入力するフィールドを新しく追加します。

ValidatorAction.java
…中略

    @Required
    @Zip
    public String zip;

…中略

    @Execute(validator = false)
    public String index() {
        byteText = "1";
        shortText = "1";
        integerText = "1";
        longText = "1";
        floatText = "1.0";
        doubleText = "1.0";
        dateText = "2008/1/1";
        emailText = "higayasuo@gmail.com";
        urlText = "http://d.hatena.ne.jp/higayasuo";
        intRangeText = "7";
        longRangeText = "7";
        floatRangeText = "7.0";
        doubleRangeText = "7.0";
        minlengthText = "123";
        maxlengthText = "1234567890";
        minbytelengthText = "ああ";
        maxbytelengthText = "あああああ";
        phoneText = "03-9999-9999";
        zip = "999-9999";
        return "validator.vm";
    }
…中略

画面(vmファイル)を修正する

validator.vm
…中略

<tr>
<td>郵便番号:</td><td><input type="text" name="zip" value="$!zip"></td>
</tr>

…中略

以上で全ての準備が完了しました。

実際動かしてみる

無事動きました。エラーメッセージもちゃんと表示されます。

まとめ

実際のPJなどでは、今回のように独自の検証を行うケースがあると思うので
今回のような作業がマニュアル化されてると嬉しいですね。

SAStrutsのドキュメント内に記述がありました。以下のリンクの最後のほうを参照です。
id:higayasuo さん、ありがとうございます。
http://sastruts.seasar.org/featureReference.html#Validator