UiBinderその2

GWTのUiBinderは単にGUIのレイアウトをXMLで記述することに留まらない素晴らしい機能がある。

AddressBookUi.xml (抜粋)
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" xmlns:g="urn:import:com.google.gwt.user.client.ui">
 <g:HTMLPanel>
   <g:Grid>
     <g:row>
       <g:customCell><g:Label ui:field="lblFullName"/></g:customCell>
       <g:customCell><g:TextBox ui:field="txtFullName" visibleLength="20"/></g:customCell>
     </g:row>
   </g:Grid>
 </g:HTMLPanel>
</ui:UiBinder> 

ここではuiネームスペースのfield属性に注目しておいてほしい。

このようなレイアウトがあるとする。UiBinderのUi.XMLにはそれをパースしてWidgetに実体化するための、対になるクラスが必要だ。(ウィザード等でUiBinderを生成すると自動的にクラスがテンプレートとして生成される)

AddressBookUi.java
public class AddressBookUi extends Composite  {
    private static AddressBookUiUiBinder uiBinder = GWT.create(AddressBookUiUiBinder.class);
    interface AddressBookUiUiBinder extends UiBinder {
    }
    public AddressBookUi() {
        initWidget(uiBinder.createAndBindUi(this));
    }

Ui.XMLに記述されたUiBinderのWidgetはデフォルトコンストラクタのコードに埋め込まれたAddressBookUiUiBinder#createAndBindUiメソッドにより実体化される。

ではこのコード中で実体化された"UiBinder Widget"にアクセスするにはどうしたら良いのだろう。

ここで先ほどUi.XMLの例を紹介した際のuiネームスペースのfield属性が登場する。実はこの属性で記述した名前を、クラス中のフィールド名として参照するのである。 そして参照するフィールドには@UiFieldアノテーションを記述するのだ。

AddressBookUi.java ( UiFieldアノテーション記述 )
public class AddressBookUi extends Composite  {
    private static AddressBookUiUiBinder uiBinder = GWT
            .create(AddressBookUiUiBinder.class);

    interface AddressBookUiUiBinder extends UiBinder {
    }
    @UiField Label lblFullName;
    @UiField TextBox txtFullName;
    :
    public AddressBookUi() {
        this.initWidget(uiBinder.createAndBindUi(this));
        this.lblFullName.setText("氏名");
    }

このように記述するとGWTはUi.XMLから実体化されたWidgetインスタンスを識別して参照を@UiFieldでアノテートされたフィールドに注入する。(これが"UiBinder"と呼ばれる所以だろう。) また、これだけであればリフレクションでもなんとかなるが、GWTはコンパイル時にui.XMLとフィールド名の相互をチェックしており、合致しない場合にエラーが発生させることが出来るのである。

Ui.XMLのui:fieldと@UiFiedを記述したフィールド名が合致せずエラーが発生している

GWTはコンパイル時にui.xmlをパースして内部にGUIウィジェットリポジトリを生成し、ランタイム時にはオーナクラスのフィールドに参照を注入する。 まるでDIコンテナのようだ。