APTでテンプレートメソッドパターンを生成する その2

前回はテンプレートメソッドパターンの実装の基となる抽象クラスと、生成するクラスのメタ情報となるアノテーションを用意した。

さてここでおさらいだ。前回用意したアノテーションを元になるクラス又はインタフェースに記述することにより、指定された抽象クラスを継承する具象クラスを生成する。大体以下のような形になる

  • 対象となるクラス(インタフェース)を用意する

XMLPullParsarをパースし、その要素をマップする型を用意するが、ここではその型そのものではなくアノテーションを記述するための土台となるクラスを用意し、アノテーションは予想されるXML要素に合わせて記述する。

    • UserInfo.java (例のため、フィールドを絞っている)
@XmlAutoBean(beandClass="net.kazzz.dto.UserInfoDto",
        elements={
            @Element(name="user-cd", fieldName="userCd"), // 利用者CD
            @Element(name="name"),                        // 名前
            @Element(name="address")                      // 住所
        })
public class UserInfo {}

ポイントとしてJavaは同名のアノテーションを同一のエレメント(この場合はクラス)に複数記述することができないので@Elementアノテーションの配列を内部に保持することで複数の要素とフィールドをマップできるようにしている所だ。
また、最初の要素名"user-cd"に対応するJavaフィールド名は"userCd"と違う名前を指定することも可能になっており、その場合はフィールド名に合わせてキャメルケースでアクセサが出力される。

そして今回のアノテーションプロセッサにより生成されるクラスは以下のようになる。

package net.kazzz.dto;

import java.io.IOException;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import  net.kazzz.dto.xml.AbstractXmlDto;

@Generated(
       value={"net.kazzz.annotation.XmlAutoBeanAnnotationProcessor"}
       , date="2011-01-02T00:21:53.295+0900")
public class UserInfoDto extends AbstractXmlDto {

    protected String userCd;
    protected String name;
    protected String address;

    /* (non-Javadoc)
     * @see parse(org.jaffa.dto.xml.AbstractXmlDto)
     */
    @Override
    public void parse(XmlPullParser parser) throws XmlPullParserException, IOException {

        int type;
        String tagName = "";

        while((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
            switch(type) {
            case XmlPullParser.START_DOCUMENT:
                break;
            case XmlPullParser.START_TAG:
                tagName = parser.getName();
                break;
            case XmlPullParser.TEXT:
                if( tagName.equalsIgnoreCase("user-cd")) {
                    this.setUserCd(parser.getText());
                } else 
                if( tagName.equalsIgnoreCase("name")) {
                    this.setName(parser.getText());
                } else 
                if( tagName.equalsIgnoreCase("address")) {
                    this.setAddress(parser.getText());
                }
                break;
            case XmlPullParser.END_TAG:
                tagName = "";
                break;
            }
        }
    }

    public String getUserCd() {
        return this.userCd;
    }

    public void setUserCd(String userCd) {
        this.userCd = userCd;
    }

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAddress() {
        return this.address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

}

こちらも特別なことはしておらず、処理としては標準的なフィールドアクセを生成することと、サアノテーションに記述された通りにパーサがパース中のXML要素の値からJavaオブジェクトのセッターを呼び出しして自身のプロパティをセットしているだけである。
java beansであることを厳密にするためにはequalsメソッドとhashCodeメソッドのオーバライドが必要だが、そもそもAndroidではJava Beansをサポートしておらず、今回は厳密な等値検査にも拘らないので、これらのメソッドの生成は割愛することにする。

アノテーションプロセッサの実装は以前に紹介した通りだが、難しい所は何も無い。

1. アノテーションが記述された型を検出する
2. 記述されたアノテーションの属性値(規定値)を読み出す
3. 属性値を使って新しいクラスの実装を出力する

次回は順を追ってアノテーションプロセッサの実装について解説していこう。