Seasar DI Container with AOP

無設定Struts概要

無設定Strutsと呼ばれる機能を説明します。 無設定StrutsはS2Strutsが提供する一機能です。

無設定Strutsを利用すると、ActionやActionFormについての設定をstruts-config.xmlに記述する必要がなくなります。 またバリデーションに関する設定をvalidator-rules.xmlに記述する必要がなくなります。 S2Strutsはクラスの命名規約やクラスに指定されたアノテーションによりそれらの設定情報を組み立てます。

無設定Strutsの利用方法

struts-config.xml

struts-config.xmlにAutoStrutsConfigRegisterPlugInを登録する必要があります。 PlugInには読み込み順があるのでValidatorPlugInより後に登録してください。

  <plug-in className="org.seasar.struts.plugin.AutoStrutsConfigRegisterPlugIn">
    <set-property property="enableJar" value="false"/>
    <set-property property="jarFilePattern" value="^My.*\.jar$"/>
    <set-property property="actionClassPattern" value="foo.bar.action.*Action"/>
    <set-property property="formClassPattern" value="foo.bar.form.*Form"/>
    <set-property property="docRoot" value="/WEB-INF/jsp"/>
    <set-property property="viewExtension" value="jsp,html,view"/>
  </plug-in>

プラグインのプロパティーには値をセットすることが可能です。各プロパティーの説明は以下になります。各プロパティーの記述を省略した場合にはデフォルト値が使用されます。

プロパティー 説明 デフォルト値
enableJar 無設定S2Strutsに含めるクラスをクラスパスに含まれているjarファイル内からも検索するか指定します。検索する場合、true。 false
jarFilePattern enableJarをtrueとしたときに検索するjarファイルのファイル名パターンを指定します。 なし
(どのjarファイルも検索対象になりません)
referenceClass 指定されたクラスが存在するディレクトリまたはjarファイルを基点として自動登録するクラスを検索します。 なし
actionClassPattern 無設定S2Strutsでactionタグの値を特定するためのActionのクラス名のパターンを指定します。 .*Action$
formClassPattern 無設定S2Strutsでform-beanタグの値を特定するためのActionFormのクラス名のパターンを指定します。 (.*Form$)|(.*Dto$)
docRoot Viewテンプレートとなるファイルの置き場所のトップディレクトリを指定します。 なし
viewExtension Viewテンプレートとなるファイルの拡張子を指定します。 jsp,html

アノテーション

無設定Strutsの設定はアノテーションを用いて行います。 アノテーションには、定数アノテーションとTigerアノテーションがあります。

アノテーションによるActionFormの定義

struts-config.xmlを記述することなくActionFormを定義するには、 ActionFormとしてのクラスをXxxFormもしくはXxxDtoという名前で作成します(Xxxは任意の名称を表します)。 推奨はXxxFormです。 StrutsのActionFormを継承する必要はありません。 validation-rule.xmlを記述することなくバリデーションを定義するには、プロパティのsetterにバリデーション用のアノテーションを指定します。

  • ActionFormの定義

    ActionFormとして扱われることを示すために、クラスに@StrutsActionFormを指定します。

    @StrutsActionForm
    public class AddForm {
        ...
    }
    

    @StrutsActionFormに指定できる属性は、struts-configのform-beanタグの属性に対応します。

  • バリデーションの定義

    プロパティのsetterにアノテーションを指定することでバリデーションの設定ができます。

    @Required
    @IntegerType
    public void setArg1(String arg1) {
        this.arg1 = arg1;
    }
    
    バリデーションのアノテーションによる設定はvalidation-rule.xmlの記述に対応します。 バリデーションのアノテーションの詳細はバリデーションを参照してください。

アノテーションによるActionの定義

struts-config.xmlを記述することなくActionを定義するには、XxxActionという名前でクラスを作成します。
  • Actionの定義 Actionとして扱われることを示すために、クラスには@StrutsActionを指定します。
    @StrutsAction(input = AddAction.ADD)
    public class AddAction {
    ...
    }
    
    @StrutsActionに指定できる属性は、struts-configのactionタグの属性に対応します。
  • Forwardの定義 ActionごとのForwardの設定として、Actionクラスのpublicでstaticなフィールドに@StrutsActionForwardを指定します。
    @StrutsActionForward
    public static final String ADD = "/WEB-INF/view/add/add.jsp";
    
    @StrutsActionForwardに指定できる属性は、struts-configのaction要素内のforwardタグの属性に対応します。path属性を指定しない場合、フィールドの値がpath属性の値とみなされます。

HOT deployとの組み合わせ

無設定StrutsはHOT deployと組み合わせて利用できます。 無設定StrutsとHOT deployを組み合わせたサンプルとしてはS2StrutsExampleを参照してください。

設定方法

HOT deployを利用するにはHOT deployの設定を参照してください。さらに、無設定StrutsとHOT deployをより緊密に連携させるために次の設定を行ってください。

s2struts.diconの修正

  • convention.diconのインクルード
    新しくインクルードします。
    <include path="convention.dicon" />
    
  • actionPathNamingRuleの設定
    DefaultActionPathNamingRuleからSubApplicationActionPathNamingRuleに変更します。
    <component name="actionPathNamingRule"
      class="org.seasar.struts.lessconfig.config.rule.impl.SubApplicationActionPathNamingRule"/>
    
  • actionFormNamingRuleの設定
    DefaltActionFormNamingRuleからSubApplicationActionFormNamingRuleに変更します。
    <component name="actionFormNamingRule"
      class="org.seasar.struts.lessconfig.config.rule.impl.SubApplicationActionFormNamingRule"/>
    

この設定を行うことで、同じサブアプリケーション内にあるActionとActionFormを命名規約で自動的に結びつけることができます。 たとえば、次のような条件があるとします。

  • ルートパッケージ名がxxx.yyy
  • Actionクラスの完全修飾名がxxx.yyy.web.add.AddAction
  • ActionFormクラスの完全修飾名がxxx.yyy.web.add.AddForm
この条件では、「add」がサブアプリケーション名となります。 このとき、AddActionのpathは「/add/add」でコンポーネント名は「add_addAction」となり、AddFormの名前は「add_addForm」となります。 しかし、上記の設定により@StrutsActionのname属性を省くことができ、またActionForm用プロパティもサブアプリケーション名を除いた名前で定義できます。
@StrutsAction(input = AddAction.ADD) // name属性の指定が不要
public class AddAction {
...private AddForm addForm;
}
ただし、JSPでは次のように、Actionのpath、コンポーネント名、ActionFormの名前を意識したコーディングが必要になるので注意してください。
<html:form action="/add/add">
  <bean:define id="form" name="add_addForm" />
  <html:text property="arg1" styleClass="number" errorStyleClass="number-error" /> + 
  <html:text property="arg2" styleClass="number" errorStyleClass="number-error" /> = 
  <bean:write name="form" property="result"/><br />
  <s2struts:submit action="@{add_addAction.calculate}">calculate</s2struts:submit>
</html:form>

注意事項

ActionFromの扱いについて

ActionFromのインスタンスは、S2コンテナによって管理されません。Strutsによって管理されます。 したがって、creator.diconやcustomizer.diconでActionFromをHOT deployの対象にしないでください(S2コンテナに登録しないでください)。 たとえば、ActionFormの名前をXxxDTOとし、creator.diconやcustomizer.diconでdtoCreatorやdotCustomizerを定義しないでください。 不具合の原因になります。 推奨は、ActionFormをXxxFormという名前にすることです。

1.3.0 RC-5以前との互換性のためにXxxFormをS2コンテナに登録するFormCreatorというクラスが存在しますが、通常は使用しないでください。

バリデーション

無設定Strutsではバリデーション用のアノテーションを提供しています。 これらのアノテーションを利用するとvalidator-rules.xmlの記述が不要になります。

バリデーション用のアノテーションは、ActionFormのプロパティに対して行います。 ValidateOrder、Args、Message以外のアノテーションは基本的なバリデータを行うために利用します。

ValidateOrder

検証する順番を制御します。指定した順番でエラーメッセージを表示します。

属性必須デフォルト値説明
value
×
999
検証する順番を指定します。

Args

メッセージで使用される置換パラメータを指定します。

属性必須デフォルト値説明
keys
×
-
メッセージで使用される置換パラメータを指定します。
","で区切ることにより複数指定できます。
定数アノテーションで","で区切る方法については「定数アノテーションの補足」を参照してください。
bundle
×
-
デフォルト以外のメッセージリソースを使用する場合、 使用するメッセージリソースのキーを指定します。
resource
×
true
keysで指定した値をリソースキーとして利用するかを指定します。
trueの場合はリソースキーとして利用し該当する値を置換パラメータとします。
falseの場合はkeysで指定した値をそのまま置換パラメータとします。
value
×
-
Argアノテーションで個別に置換パラメータを指定する場合に使用します。
個別に置換パラメータを指定する場合は、keys、bundle、resourceを指定しないで下さい。

Arg

メッセージで使用される置換パラメータを個別に指定します。

属性必須デフォルト値説明
key
-
メッセージで使用される置換パラメータを指定します。
name
×
-
置換パラメータを使用するバリデータの名前を指定します。
bundle
×
-
デフォルト以外のメッセージリソースを使用する場合、 使用するメッセージリソースのキーを指定します。
resource
×
true
keyで指定した値をリソースキーとして利用するかを指定します。
trueの場合はリソースキーとして利用し該当する値をメッセージとします。
falseの場合はkeyで指定した値をそのままメッセージとします。
position
×
-
置換パラメータの位置を指定します。

定数アノテーションでは、以下のように プロパティー名_VALIDATOR_ARG で指定します。 複数指定する場合は、定数名の最後にゼロからのINDEXをつけます。

    public static final String value_VALIDATOR_0 = "required";
    public static final String value_VALIDATOR_1 = "integer";
    public static final String value_VALIDATOR_ARG_0 = "form.value";
    public static final String value_VALIDATOR_ARG_1 = "form.value.def";
    public static final String value_VALIDATOR_ARG_2 = "form.value.req, name = required, position = 1";

    public void setValue(String value) {
        this.value = value;
    }

Messages

複数のMessageアノテーションを指定したい場合に使用します。

属性必須デフォルト値説明
value
-
複数のMessageアノテーションを指定します。

Message

デフォルトメッセージの代わりに個別のメッセージを表示したい場合に指定します。

属性必須デフォルト値説明
key
-
メッセージのキー又はメッセージを指定します。
name
-
メッセージを指定するバリデータの名前を指定します。
bundle
×
-
デフォルト以外のメッセージリソースを使用する場合、 使用するメッセージリソースのキーを指定します。
resource
×
true
keyで指定した値をリソースキーとして利用するかを指定します。
trueの場合はリソースキーとして利用し該当する値をメッセージとします。
falseの場合はkeyで指定した値をそのままメッセージとします。

Required

値に空白以外の文字が含まれてるか確認します。 引数はありません。

Mask

値がpatternで指定された正規表現と一致するか確認します。

属性必須デフォルト値説明
pattern
-
正規表現を指定します。
messageKey
×
-
メッセージを取得するキーを指定します。
resource
×
true
keysで指定した値をリソースキーとして利用するかを指定します。
trueの場合はリソースキーとして利用し該当する値を置換パラメータとします。
falseの場合はkeysで指定した値をそのまま置換パラメータとします。

IntRange, LongRange, FloatRange, DoubleRange

値がminとmaxで指定された範囲内であるか確認します。

属性必須デフォルト値説明
min
-
値範囲の最小値を指定します。
max
-
値範囲の最大値を指定します。

Maxlength

値の文字数がvalue以下であるか確認します。

属性必須デフォルト値説明
value
-
値の長さの上限値を指定します。

Minlength

値の文字数がvalue以上であるか確認します。

属性必須デフォルト値説明
value
-
値の長さの下限値を指定します。

Maxbytelength

値のバイト数がvalue以下であるか確認します。

属性必須デフォルト値説明
value
-
値の長さの上限値を指定します。
charset
×
-
バイト数で検証する場合の文字セットを指定します。
指定しない場合は、プラットフォームのデフォルト文字セットを使用します。

Minbytelength

値のバイト数がvalue以上であるか確認します。

属性必須デフォルト値説明
value
-
値の長さの下限値を指定します。
charset
×
-
バイト数で検証する場合の文字セットを指定します。
指定しない場合は、プラットフォームのデフォルト文字セットを使用します。

ByteType, ShortType, IntegerType, LongType, FloatType, DoubleType

値が該当する型に変換できるか確認します。 属性はありません。

DateType

値が有効な日付を表すか確認します。

属性必須デフォルト値説明
pattern
×
s2struts.dionのdateConfigRegisterコンポーネント定義時に指定したパターン
日付のパターンを指定します。

CreditCardType

値が有効なクレジットカード番号とみなされるか確認します。 属性はありません。

EmailType

値が有効なEメールアドレスとみなされるか確認します。 属性はありません。

UrlType

値が有効なURLとみなされるか確認します。

属性必須デフォルト値説明
allowallschemes
×
false
schemeを許可するかどうかを指定します。
trueを設定するとすべてのschemeが許可されます。
allow2slashes
×
false
ダブルスラッシュ(//)を許可するかどうかを指定します。
trueを設定すると許可されます。
nofragments
×
false
URLの分割を許可するかどうかを指定します。
falseを設定すると許可されます。
schemes
×
http,https,ftp
許可するschemeを,(カンマ)区切りで指定します。

NoValidate

自動的にバリデーションを行わないように指定します。 属性はありません。

定数アノテーションの補足

定数アノテーションでは、属性の区切り文字として「,」(カンマ)を利用しています。 値に「,」を指定する場合は以下のように値を「'」(シングルコーテーション)または「"」(ダブルコーテーション)で囲んでください。

 public static final String value_VALIDATOR = "mask, pattern='(^[0-9]{1,2}$)', messageKey=comma";

 public static final String value_VALIDATOR = "mask, pattern=\"(^[0-9]{1,2}$)\", messageKey=comma";

カスタムバリデータの作成

Strutsでの新規Validation作成

Struts(commons validator)としての新規Validationを追加するには、

  • 検証用クラスの作成
  • validator-rules.xmlへ設定情報の追加
を行います。 Struts Validator Guideに、Strutsでの新規Validationを追加する方法が記述されています。 こちらも参考にしてください。

2つの入力内容が同じか検証するクラスは以下のようになります。

package org.seasar.struts.examples.validator;

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.commons.validator.util.ValidatorUtils;
import org.apache.struts.action.ActionMessages;
import org.apache.struts.validator.Resources;

public class MyFieldChecks {

    public static boolean validateTwoFields(Object bean,
            ValidatorAction validatorAction, Field field,
            ActionMessages errors, Validator validator,
            HttpServletRequest request) {

        String value = ValidatorUtils.getValueAsString(bean, field.getProperty());
        String sProperty2 = field.getVarValue("secondProperty");
        String value2 = ValidatorUtils.getValueAsString(bean, sProperty2);

        if (!GenericValidator.isBlankOrNull(value)) {
            try {
                if (!value.equals(value2)) {
                    errors.add(field.getKey(), Resources.getActionMessage(
                            validator, request, validatorAction, field));

                    return false;
                }
            } catch (Exception e) {
                errors.add(field.getKey(), Resources.getActionMessage(
                        validator, request, validatorAction, field));
                return false;
            }
        }

        return true;
    }
}

最初に検証を行うプロパティの値を取得します。 次にvalidation設定の"secondProperty"変数に指定したプロパティ名を取得しそのプロパティの値を取得します。 最後にその2つの値を比較し、正しい値か確かめています。 ここでは、"secondProperty"という変数が必要になるところがポイントです。 この変数はValidationアノテーションを作成するときのプロパティとして宣言することになるからです。

次に上記のクラスをvalidator-rules.xmlに追加します。 validatorタグのname属性(validator name)に指定する内容は、アノテーション名と関連があります。 S2Strutsでは以下の規則によりアノテーション名を変換しvalidator nameと一致するか判断して特定します。

  • アノテーション名の先頭文字を小文字にする
  • アノテーション名の最後が"Type"で終わっている場合それを除く
例えば、Hogeアノテーションの場合のvalidator nameは"hoge"となり、FooTypeアノテーションの場合のvalidator nameは"foo"となります。

今回はアノテーション名をTwoFieldsとするためnameは"twoFields"とします。validator-rules.xmlへは以下の内容を追加します。

      <validator name="twoFields"
            classname="org.seasar.struts.examples.validator.MyFieldChecks"
               method="validateTwoFields"
         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.twoFields"/>

msg属性に"errors.twoFields"と指定したので、このメッセージKeyをapplication.propertiesに追加します。

errors.twoFields={0} has to have the same value as the confirm field.

ここまでがStrutsでの新規Validation作成作業です。

Validationアノテーションの作成

Validationアノテーションの作成は

  • アノテーションの定義
  • ConfigRegisterの作成
を行います。

S2Strutsの提供するアノテーションは、定数アノテーション、Tigerアノテーション、Backport175アノテーションの3種類があります。 定数アノテーションとして利用する場合はアノテーションの定義は必要ありません。 Tigerアノテーションとして利用する場合は、メタアノテーションとしてorg.seasar.struts.validator.annotation.tiger.ValidatorTargetを指定し以下のように作成します。

package org.seasar.struts.examples.validator.annotation.tiger;

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

import org.seasar.struts.validator.annotation.tiger.ValidatorTarget;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@ValidatorTarget
public @interface TwoFields {

    String secondProperty();

}

Backport175アノテーションとして利用する場合は、メタアノテーションとしてorg.seasar.struts.validator.annotation.backport175.ValidatorTargetを指定し以下のように作成します。

package org.seasar.struts.examples.validator.annotation.backport175;

/**
 * @org.seasar.struts.validator.annotation.backport175.ValidatorTarget
 */
public interface TwoFields {

    String secondProperty();

}

今回は検証するためにsecondPropertyが必要となるため上記のようになりました。 validation設定で変数が必要ない場合はプロパティを定義する必要はありませんし、これから作成するConfigRegisterは必要ありません。

アノテーションで取得した値はConfigRegisterを作成し設定する必要がありますので、 TwoFieldsConfigRegisterImplを作成します。

TwoFieldsConfigRegisterImplは、org.seasar.struts.lessconfig.validator.config.ConfigRegisterを実装します。 registerメソッドの引数はfieldとparameterです。 fieldは、フィールドに対して行う妥当性チェックとエラーメッセージの生成に使用する入れ替え可能な妥当性チェックのリストとメッセージの情報と値を内部に持ちます。 つまりValidationの内容を格納するオブジェクトです。 parameterは、アノテーションで定義したメソッド名をkey、メソッドの戻り値をvalueとしたMapです。

package org.seasar.struts.examples.validator.config;

import java.util.Map;

import org.apache.commons.validator.Field;
import org.apache.commons.validator.Var;
import org.seasar.struts.lessconfig.validator.config.ConfigRegister;

public class TwoFieldsConfigRegisterImpl implements ConfigRegister {

    public void register(Field field, Map parameter) {
        String secondProperty = (String) parameter.get("secondProperty");

        Var var = new Var();
        var.setName("secondProperty");
        var.setValue(secondProperty);
        field.addVar(var);
    }

}

作成したConfigRegisterはコンポーネントとして登録する必要があります。 登録するときのコンポーネント名は、validator nameのときと同様のアノテーション名変換を行い"ConfigRegister"を付け加えた名前とします。 例えば、Hogeアノテーションの場合は"hogeConfigRegister"となり、FooTypeアノテーションの場合は"fooConfigRegister"となります。

今回はコンポーネントとして登録するために新規でvalidator.dionを作成します。

<?xml version="1.0" encoding="Shift_JIS"?>
<!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN"
    "http://www.seasar.org/dtd/components21.dtd">
<components>
    <component name="twoFieldsConfigRegister"
            class="org.seasar.struts.examples.validator.config.TwoFieldsConfigRegisterImpl"/>
</components>

そしてapp.diconにincludeを追加して、validator.dionを読み込むようにします。

    <include path="validator.dicon"/>

ここまでがS2Strutsでの新規アノテーションの作成作業です。

これでアノテーションを使用したValidation作成作業は完了です。

動作確認

作成したTwoFieldsアノテーションを試すには、

  • Viewの作成
  • Actionの作成
  • Formの作成
を行います。

まずはViewの作成です。ここではJSPをViewとして利用します。確認用のため簡単な作りです。

<%@ page contentType="text/html;charset=Windows-31j" language="java" %>
<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
<%@ taglib uri="http://www.seasar.org/tags-s2struts" prefix="s2struts" %>

<html>
<head>
  <title>Two Fields Test</title>
</head>
<body>
  <html:errors />

  <html:form action="/twoFields" method="POST">
    <s2struts:page/>
    <table>
      <tr>
        <td>field</td>
        <td><html:text property="field"/></td>
      </tr>
      <tr>
        <td>confirm field</td>
        <td><html:text property="confirmField"/></td>
      </tr>
    </table>
    <html:submit/>
  </html:form>
</body>
</html>

次はActionの作成です。今回はPOJOのActionで無設定機能(詳細は「無設定S2Strutsリファレンス」を参照)を使います。 Actionのインターフェースと実装は以下のようになります。

package org.seasar.struts.examples.validator;

public interface TwoFieldsAction {
    
    String execute();

}
package org.seasar.struts.examples.validator;

public class TwoFieldsActionImpl implements TwoFieldsAction {

    public String execute() {
        return "success";
    }

}

Actionの処理は"success"を返すだけですがTwoFieldsアノテーションの動作確認には十分です。

Actionはコンポーネントとして登録する必要があります。新規に作成したtwoFields.diconは以下のようになります。

<?xml version="1.0" encoding="Shift_JIS"?>
<!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN"
    "http://www.seasar.org/dtd/components21.dtd">
<components>
    <component name="twoFieldsAction"
            class="org.seasar.struts.examples.validator.TwoFieldsActionImpl"
            instance="request" />
</components>

そしてapp.diconにincludeを追加して、twoFields.diconを読み込むようにします。

    <include path="org/seasar/struts/examples/dicon/twoFields.dicon"/>

最後にFormを作成します。例として定数アノテーションの場合とTigerアノテーションの場合の2つのFormを以下に記述します。 利用するアノテーションでFormを作成してください。

package org.seasar.struts.examples.validator;

import java.io.Serializable;

public class TwoFieldsForm implements Serializable {

    private static final long serialVersionUID = 1L;

    private String field = "";

    private String confirmField = "";
    
    public String getField() {
        return field;
    }
    
    public static final String field_VALIDATOR_0 = "required";

    public static final String field_VALIDATOR_1 = "twoFields, secondProperty = confirmField";

    public static final String field_VALIDATOR_ARGS = "Field, resource=false";

    public void setField(String field) {
        this.field = field;
    }

    public String getConfirmField() {
        return confirmField;
    }

    public static final String confirmField_VALIDATOR = "required";

    public static final String confirmField_VALIDATOR_ARGS = "ConfirmField, resource=false";

    public void setConfirmField(String confirmField) {
        this.confirmField = confirmField;
    }

}
package org.seasar.struts.examples.validator;

import java.io.Serializable;

import org.seasar.struts.examples.validator.tiger.TwoFields;
import org.seasar.struts.validator.annotation.tiger.Args;
import org.seasar.struts.validator.annotation.tiger.Required;

public class TwoFieldsForm implements Serializable {

    private static final long serialVersionUID = 1L;

    private String field = "";

    private String confirmField = "";
    
    public String getField() {
        return field;
    }
    
    @Required
    @TwoFields(secondProperty="confirmField")
    @Args(keys = "Field", resource = false)
    public void setField(String field) {
        this.field = field;
    }

    public String getConfirmField() {
        return confirmField;
    }

    @Required
    @Args(keys = "ConfirmField", resource = false)
    public void setConfirmField(String confirmField) {
        this.confirmField = confirmField;
    }

}

これで確認ができます。 Tomcatを起動して、ブラウザからhttp://localhost:8080/s2struts-example/pages/twoFields.jspにアクセスし動作確認してください。

新規にアノテーションを使用したValidationを作成するのは通常より大変な作業かもしれませんが、一度作成すれば簡単にFormで使えるようになると思います。 作成したときの苦労を十分回収することができるのではないでしょうか?

独自のValidationを作ってみませんか?