あまり考えず、Modelを使っていた(使っていなかった?)ので、
ふと調べてみたところ、いろいろできそうだったので、
調べてみた結果をまとめてみます。
Example ソースコードに対するリンク集。

使用しているWicketのVersion

7.2.0


Modelについての説明文書

以下のWeb上の文書でWicketのModelとは何かは理解できそうです。


Modelパッケージ配下のClass一覧

wicket/wicket-core/src/main/java/org/apache/wicket/model at wicket-7.x · apache/wicket · GitHub
から一覧表は作成しました。

Class名 Notes
AbstractPropertyModel.java PropertyModel.javaの基底クラス 省略
AbstractReadOnlyModel.java ReadOnlyを保証したい時に使う
AbstractWrapModel.java ModelオブジェクトをWrapして、一部を加工する時に使用する
ChainingModel.java PropertyModel.java,CompoundPropertyModel.javaの基底クラス 省略
ComponentDetachableModel.java シリアライズするには忍びない大きいオブジェクト生成時に使用する
ComponentModel.java Panel等ページテンプレートクラスにデータクラスを設定
ComponentPropertyModel.java Panel等ページテンプレートクラスにデータクラスを設定、値はコピーしてくれる
CompoundPropertyModel.java 値は自動コピーもする。単純コピーでないものはbindできる。
IChainingModel.java IFなので省略
IComponentAssignedModel.java IFなので省略
IComponentInheritedModel.java IFなので省略
IDetachable.java IFなので省略
IModel.java IFなので省略
IModelComparator.java IFなので省略
IObjectClassAwareModel.java IFなので省略
IPropertyReflectionAwareModel.java IFなので省略
IWrapModel.java IFなので省略
LoadableDetachableModel.java Sessionに大きなデータを積まないようにするためのModel
Model.java オーソドックなModel
PropertyModel.java CompoundPropertyModel.javaがあるので、あまり使用機会はないかもしれない
ResourceModel.java ResourceBundleを扱う際に使用するModel
StringResourceModel.java メッセージ出力時などに使用する。1つだけならgetString()

AbstractReadOnlyModel.java


AbstractWrapModel.java

大きいModelがあるとして、その中の一部のデータを取り出して使用する用途に使うModelかと思います。
大元のモデルが変われば、そのモデルに連動して、
AbstractWrapModel.javaを使用したModelの返すデータが切り替わる。


ComponentDetachableModel.java

exmampleが見つからなかったです..


ComponentModel.java

exmampleが見つからなかったです..
参考情報もなしですが、
ComponentPropertyModel.javaのexmampleはあるため使いかたの想像はできる。
実装を見るかぎり、あまり使う機会はなさそう.


ComponentPropertyModel.java

Panelとデータを切り離すための、modelに見受けられます。
Panelはデンプレートで、内部のデータをコントロールしたい時に使用する。
単純なデータクラスから、値のコピーの場合は、このクラスを、
単純なコピーでない場合、 上記のComponentModel.javaを使う。


CompoundPropertyModel.java

このクラスはよく使いそうです。
使い方を詳細に調べてみました。

関連:ListItem#setModel()について

ListItemには、ListItem#setModel()、ListItem#setDefaultModel()がある。
setDefaultModel()は、Generics化の際に追加されたメソッドなので、
java5以降で実装しているなら、特に使用しなくてよい。

  • ListItem#setDefaultModel()
        CompoundPropertyModel<Blog> blogModel = new CompoundPropertyModel<>(item.getModelObject());
        item.setDefaultModel(blogModel);
    

ではなくて、以下の記述でよい。


関連:MarkupContainer#setDefaultModel()について

Pageクラス、Panelクラス等には、setModel()はなく、setDefaultModel()だけがある。
※setModel、getModelが使う機会がないから?


関連:BoundCompoundPropertyModelについて

wicket1.4くらいまでは、BoundCompoundPropertyModelというclassがあり、
以下の、bindメソッドがあった。

  • BoundCompoundPropertyModel#bind(final Component component, final String propertyExpression)

        /**
         * Adds a property binding.
         * 
         * @param component
         *            The component to bind
         * @param propertyExpression
         *            A property expression pointing to the property in this model
         * @return The component, for convenience in adding components
         */
        public Component bind(final Component component,
                final String propertyExpression) {
            bind(component, propertyExpression, null);
            return component;
        }
    

  • BoundCompoundPropertyModel#bind(final Component component, final Class type)

        /**
         * Adds a type conversion binding.
         * 
         * @param component
         *            The component to bind
         * @param type
         *            The type of the property
         * @return The component, for convenience in adding components
         */
        public Component bind(final Component component, final Class type) {
            bind(component, component.getId(), type);
            return component;
        }
    

wicket1.4でBoundCompoundPropertyModelは、非推奨クラスになり、wicket1.5以降は削除されている。
上記のbindメソッドの代わりに?、CompoundPropertyModelにbindメソッドが追加された。

  • CompoundPropertyModel#bind(String property)
        /**
         * Binds this model to a special property by returning a model that has this compound model as
         * its nested/wrapped model and the property which should be evaluated. This can be used if the
         * id of the Component isn't a valid property for the data object.
         * 
         * @param property
         *      the name that will be used to find
         * @return The IModel that is a wrapper around the current model and the property
         * @param <S>
         *            the type of the property
         */
        public <S> IModel<S> bind(String property)
        {
            return new PropertyModel<>(this, property);
        }
    

関連:PropertiesListViewについて

ListViewで、CompoundPropertyModelを使えるようになる。
ものとして認識しました。 以下のように書けます。 CompoundPropertyModel#bind()とかしたい場合は、
ListItem#getModel()の戻りを、Castする必要があり、それが不恰好ですね..

        // -------------------------------------------
        // New LitView
        ListView<Video> videoListView = new PropertyListView<Video>("videos", videos) {

            private static final long serialVersionUID = 4949588177564901031L;

            @Override
            protected void populateItem(ListItem<Video> item) {
                item.add(new Label("title"));
                WebComponent webComponent = new WebComponent("videoSrc");

                CompoundPropertyModel<Video> model = (CompoundPropertyModel<Video>) item.getModel();
                webComponent.add(AttributeModifier.replace("src", model.bind("embedUrl")));
                item.add(webComponent);
            }
        };
        // --------------------
        add(videoListView);

正直使えるユースケースが少ない? ように感じました。
ListItem直下の階層に対してしか使えない?
それほど、直下の階層にプロパティ値を設定することは少ないように思います。
設定できるプロパティと出来ないプロパティが混じり、ListViewでいいのではとなりそうです。
中、大規模開発だったら、ListViewしか使わないか、ハイブリッドOKかを決めておく方か吉かもしれません。


LoadableDetachableModel.java

Sessionに積んで、シリアライズするには大きすぎるオブジェクト(きっとListデータ)を、
Sessionには設定せず、毎回ストレージから読み出す用途に使用します。

  • 試しにLoadableDetachableModelを記載したプログラムの抜粋 FestivalRepositoryはJPAのリポジトリクラスで全件リスト 取得処理が走ります。
        LoadableDetachableModel<List<Festival>> festivals = new LoadableDetachableModel<List<Festival>>() {
            private static final long serialVersionUID = 7474274077691068779L;

            @Override
            protected List<Festival> load() {
                // Get ListView Elems
                FestivalRepository repository = InjectorHolder._new(FestivalRepository.class);
                return repository.findAll();
            }
        };

Model.java

簡単な動的Modelを作るために使用するものだという理解です。 getObjectを実装して、Method内で値を取得。


PropertyModel.java

ComponentPropertyModelを使う機会が多いかと思います。


ResourceModel.java

あまり使用する機会はなさそうです。
StringResourceModel.javaの方にはメッセージ設定機能があり、こちらにはありません。
単純な文字列の取得ではない場合、getString()ではなくこちらで実装する。


StringResourceModel.java

以下、サイトの説明がわかりやすかったです。
StringResourceModelは、LoadableDetachableModelを継承しているので、
シリアライズの対象外になりそうです。


包括的な日本語ドキュメントや書籍が少ないのは、
やはりちょっと学習するの大変に思います。

以上です。

コメント

カテゴリー