cypher256's blog

Pleiades とか作った

検証用アノテーション

SAStruts では Struts 標準の入力チェックに対応するアノテーションが用意されていて、Mask を使えば大概のことはできますが、それだけだと実際の業務プロジェクトでは開発者が苦労することになります。小数点を含む数値に @DoubleType とか使うと "1d" とか "1f" が通っちゃいますからね。

そこで検証用アノテーションを作ることになります。こんな。

// 数値チェック・アノテーション
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@Validator("numberCheck")
public @interface NumberCheck {
    /** 数値最大桁数 (数字全体の最大有効桁数 例)123.4 -> 4) */
    int maxlength();
    /** 小数部桁数 */
    int scale() default 0;
    /** 最小値 */
    double min() default 0;
    /** 最大値 */
    double max() default Double.MAX_VALUE;
    /** 検証の対象となるメソッド名を指定 (複数ある場合はカンマ区切り) */
    String target() default "";
}
// フォーム・クラス
@Component(instance = InstanceType.SESSION)
public class HogeDto implements Serializable {
    @NumberCheck(maxlength = 5)
    public String xxx;
    @NumberCheck(maxlength = 5, scale = 2)
    public String yyy;
    @NumberCheck(maxlength = 5, scale = 2, min = -100, max = 100)
    public String zzz;
}


チェックの実装は Struts の FieldChecks や SAStruts の S2FieldChecks が参考になりますが、上記のようなアノテーションの場合、チェック結果によりメッセージを切り替えなければなりません。例えば、不正フォーマット時、整数桁数エラー、小数部桁数エラー、全体桁数エラー、範囲エラーなどがあります。参考となる FieldChecks は 1 つのメッセージしか対応していないため、メッセージを可変にする場合は、下記のように commons validator のメッセージを自分で生成する必要があります。

public class HogeFieldCheckes implements Message {

    // @NumberCheck に対応したチェック
    public static boolean validateNumber(Object bean, ValidatorAction va,
            Field field, ActionMessages errors, Validator validator,
            HttpServletRequest request) {

        // エラー・コンテキストの生成
        ErrorsContext context = new ErrorsContext(
            va,
            field,
            errors,
            validator,
            request);
        try {
            String value = ValidatorUtils.getValueAsString(bean, field
                .getProperty());

            if (GenericValidator.isBlankOrNull(value)) {
                return true;
            }
            // 数値チェック
            if (数値エラー) {
                context.add(ERRORS_COMMON_NUMBER);
                return false;
            }
            // 桁数チェック
            Double doubleValue = Double.parseDouble(value);
            Integer length = Integer.parseInt(field.getVarValue("maxlength"));
            Integer scale = Integer.parseInt(field.getVarValue("scale"));
            if (整数部桁数エラー) {
                context.add(ERRORS_COMMON_NUMBER_INTEGER);
                return false;
            }
            if (全体桁数エラー) {
                context.add(ERRORS_COMMON_LENGTH);
                return false;
            }
            if (小数部桁数エラー) {
                context.add(ERRORS_COMMON_NUMBER_SCALE);
                return false;
            }
            // 範囲チェック
            Double min = Double.parseDouble(field.getVarValue("min"));
            Double max = Double.parseDouble(field.getVarValue("max"));
            if (範囲エラー) {
                context.add(ERRORS_COMMON_NUMBER_RANGE);
                return false;
            }
        } catch (Exception e) {
            context.add(ERRORS_COMMON_NUMBER);
            return false;
        }
        return true;
    }

上記で生成しているエラー・コンテキストは下記のような commons validator のメッセージを作成するためのクラスです。

    // エラー・コンテキスト・クラス
    private static class ErrorsContext {

        private final ValidatorAction va;
        private final Field field;
        private final ActionMessages errors;
        private final Validator validator;
        private final HttpServletRequest request;

        // コンストラクタ
        public ErrorsContext(ValidatorAction va, Field field,
                ActionMessages errors, Validator validator,
                HttpServletRequest request) {
            this.va = va;
            this.field = field;
            this.errors = errors;
            this.validator = validator;
            this.request = request;
        }

        // エラー追加
        public void add(String key, Object... args) {
            Msg m = new Msg();
            m.setName(field.getDepends());
            m.setKey(key);
            m.setResource(true);
            field.addMsg(m);
            for (int i = 0; i < args.length; i++) {
                Arg a = new Arg();
                a.setKey(String.valueOf(args[i]));
                a.setResource(false);
                a.setPosition(i);
                field.addArg(a);
            }
            errors.add(field.getKey(), Resources.getActionMessage(
                validator,
                request,
                va,
                field));
        }
    }