フォームの複数の要素をまとめて1つのパネルにする方法

RDBテーブルのカラムのデータ型に合った検索条件入力部を作ろう!となったときに、データ型に合った条件を入力できるパネルがあればいいなと思いました。
(例えば、文字列での検索の場合は条件と部分一致か完全一致かのプルダウンを付ける、とか、日付の場合、From条件、To条件およびそれらにカレンダーを付与、とか)

このような処理の場合、条件を入力できる部分が複数個あっても、返す値(オブジェクト)は一つである、ということがキモになるかと思います。あまり個々の値を返されても嬉しくないと思うので、パネル内で入力された値をもとに、1つの値(オブジェクト)を返してしまうのがよいでしょう。

方法としては、http://wicket.apache.org/docs/wicket-1.3.2/wicket/apidocs/org/apache/wicket/markup/html/form/FormComponentPanel.htmlを使用します。

例えば、文字列検索を行うようなパネルを作るとします。
HTML側は以下の様に、wicket:panelタグで括ります。

<wicket:panel>
  <select wicket:id="condition">
    <option value="0">一致条件</option>
  </select>
  <input type="text" wicket:id="query" />
</wicket:panel>

対応するJavaは以下のような感じでしょうか。

public class StringCondPanel extends FormComponentPanel {
    private DropDownChoice condComponent;
    private TextField queryComponent;
    
    private int condition = 1;
    private String query;
    
    private static final List<Integer> CONDITIONS = Arrays.asList(
        new Integer[]{Integer.valueOf(1),Integer.valueOf(2),Integer.valueOf(3)});

    public FieldCondPanel(String id) {
        super(id);
        init();
    }

    public FieldCondPanel(String id, IModel model) {
        super(id, model);
        init();
    }

    private void init() {
        condComponent = new DropDownChoice("condition", new PropertyModel(this, "condition"), CONDITIONS);
        condComponent.setRequired(true);
        //1,2,3に完全一致、部分一致、不一致をマッピングする
        condComponent.setChoiceRenderer(new IChoiceRenderer() {
            public Object getDisplayValue(Object object) {
                int value = (Integer)object;
                String result;
                switch (value) {
                    case 1: result = "完全一致"; break;
                    case 2: result = "部分一致"; break;
                    default: result = "不一致"; break;
                }
                return result;
            }

            public String getIdValue(Object object, int index) {
                return String.valueOf(CONDITIONS.get(index));
            }
            
        });
        add(condComponent);
        
        add(queryComponent = new TextField("query", new PropertyModel(this, "query")));
    }

    public int getCondition() {
        return condition;
    }

    public void setCondition(int condition) {
        this.condition = condition;
    }

    public String getQuery() {
        return query;
    }

    public void setQuery(String query) {
        this.query = query;
    }

    @Override
    protected void convertInput() {
        //検索条件と一致条件を取得して自前でセット
        query = (String) queryComponent.getConvertedInput();
        condition = (Integer) condComponent.getConvertedInput();
        //条件を生成してください
        String strCond = ""; //ここに条件を書くか、専用のクラスを作っておく
        //IModel.getObject()で取得したい値をセットする
        setConvertedInput(strCond);
    }
}

ここで大事なのは、convertInput()メソッドです。convertInput()メソッド内で、ポストされてきた条件を受け取り、必要な値(オブジェクト)に加工して、setConvertedInput(obj)でセットする必要があります。
また、私がハマッたのですが、queryとconditionはCompoundPropertyModelで値がセットされるから、queryComponent.getConvertedInput()で値を取得しなくてもいいじゃないかと思い、省略してコンパイル、実行したところ、setConvertedInputには予期せぬ値が入っていました。

原因は、デバッガ等で追いかけたところによると、CompoundPropertyModelによって値をセットするよりも前に、convertInput()メソッドが呼ばれてしまうためです。その結果、queryComponent, condComponentにはフォームからの値が入っていますが、query, conditionには値が入っていない、という事態になるわけです。

(ちなみに、*Component.getConvertedInput()が呼ばれたものについては、convertInput()メソッドの実行後に呼ばれるCompoundPropertyModelによる値のセットは省略されるようです。呼ばれていないものについては値をセットします。)

さて、肝心の条件部分の生成は置いておいてしまいましたが、何とか複数の入力を1つにまとめるパネル作りは何とかなりそうです。
次の目標は、上記のようなパネルをループで複数個生成できるのか、そして複数個の値を保持できるModelはあるのか、要調査です。

参考ページ http://www.wicket-library.com/wicket-examples/forminput