AjaxFallbackDefaultDataTableに関するメモ - その4

今回は表示する時にいろいろ手を加える際(例えば日付のフォーマット等)のやりかたメモ。
「Countryの各フィールドの値に対して「*」等を前後に付加する」みたいな処理をする場合は下記のようになります。

    /**いろいろ省略**/
        columnList.add(new PropertyColumn(new Model("ID"),"id","countryId"){
            @Override
            public void populateItem(Item item, String componentId, IModel model) {
                Country c = (Country)model.getObject();
                item.add(new Label(componentId,"* "+c.getCountryId()+" *"));
            }
        });
        columnList.add(new PropertyColumn(new Model("Name"), "countryName"){
            @Override
            public void populateItem(Item item, String componentId, IModel model) {
                Country c = (Country) model.getObject();
                item.add(new Label(componentId, "- " + c.getCountryName() + " -"));
            }
        });
        columnList.add(new PropertyColumn(new Model("Lang"), "lang"){
            @Override
            public void populateItem(Item item, String componentId, IModel model) {
                Country c = (Country) model.getObject();
                item.add(new Label(componentId, "+ " + c.getLang() + " +"));
            }
        });

1番最初のエントリーにて『列毎に表示する感じをうける』と書いたのはこのせいです。
ListView とかだと1行毎に処理をするって感じがして直感的だと思いますが、上記の場合はいちいち各カラム毎にpopulateItemをオーバーライドして Countryオブジェクトを取得して・・・といった面倒な処理が発生してしまいます。この点が個人的に不満なところです。可読性も良いとは言えませんしねぇ。
こういう場合はViewHelperを作成するのがいいんじゃないかと思います。
例えばこんなクラスを作成し

public class CountryViewHelper implements Serializable{

    private Country country;

    public CountryViewHelper(Country country) {
        this.country = country;
    }

    public String getCountryId(){
        return "* "+country.getCountryId()+" *";
    }

    public String getCountryName(){
        return "- "+country.getCountryName()+" -";
    }

    public String getLang(){
        return "+ " + country.getLang() + " +";
    }
}

次にCountryDataProviderをちょっと変更します。

    private class CountryDataProvider extends SortableDataProvider {
        /*** 省略 ***/
        @Override
        public IModel model(final Object object) {
            return new LoadableDetachableModel(){
                @Override
                protected Object load() {
                    //ここでViewHelperを返す。
                    return new CountryViewHelper((Country)object);
                }
            };
        }
    }

こうするとPropertyColumnを生成する箇所はわざわざpopulateItemをオーバーライドすることなく下記のように前回までのシンプルなソースになります。

        columnList.add(new PropertyColumn(new Model("ID"),"id","countryId"));
        columnList.add(new PropertyColumn(new Model("Name"), "countryName"));
        columnList.add(new PropertyColumn(new Model("Lang"), "lang"));

ViewHelper はJSPベースのフレームワークだとカスタムタグによって実現されることが多いと思いますが、Wicketの場合POJOとして作成でき、単体テストとかバリバリやれます。この点は自分がWicket大好きな理由の1つです。Viewの部分をJavaリファクタリングしまくれるこの楽しさ!!   ・・・なんか話の方向が変わっちゃったけど(゚ε゚)キニシナイ

しかし、実はLoadableDetachableModelのloadにてViewHelperオブジェクトを返すというやり方は1.3までなんですよねぇ〜(やろうと思えば1.4でもいけますが・・)。1.4からはGenerics対応になるので、上記にて厳密に型パラメータを定義する場合は下記のようになります。

    private class CountryDataProvider extends SortableDataProvider<Country> {
        /*** 省略 ***/
        @Override
        public IModel<Country> model(final Country country) {
            return new LoadableDetachableModel<Country>(){
                @Override
                protected Country load() {
                    //コンパイルエラー><
                    return new CountryViewHelper(country);
                }
            };
        }
    }

LoadableDetachableModelにて型パラメーターを定義せずmodelメソッドに@SuppressWarnings("unchecked")を追加すればOKではあるんですがなんか美しくない・・・・。
他の方法としては、PropertyColumnのcreateLabelModelメソッドにてを拡張するのがいいのかなぁ。
下記のようなPropertyColumnのサブクラスを1つ作成しておくとか??

    private class MyPropertyColumn extends PropertyColumn<Country>{
        public MyPropertyColumn(IModel<String> displayModel, 
                                    String propertyExpression) {
            super(displayModel, propertyExpression);
        }

        public MyPropertyColumn(IModel<String> displayModel, 
                                  String sortProperty, 
                                  String propertyExpression) {
            super(displayModel, sortProperty, propertyExpression);
        }

        @Override
        protected IModel<?> createLabelModel(final IModel<Country> rowModel) {
            IModel<CountryViewHelper> model =  
                         new LoadableDetachableModel<CountryViewHelper>() {
                @Override
                protected CountryViewHelperload() {
                    return new CountryViewHelper(rowModel.getObject());
                }
            };
            return new PropertyModel<CountryViewHelper>(model,getPropertyExpression());
        }
    }

一応こっちのほうがよさげですかねぇ。

ん??ということは1.3の場合もCountryDataProvider#modelメソッドを変更するのではなく上記MyPropertyColumnのようなクラスを作成したほうがいいということですかね??

う〜ん、なんか中途半端でゴメンナサイ・・・。
間違ってるところとか勘違いしている点がある場合、ご指摘しただけると嬉しいです。