How to use maru-dog Beanプロパティデータバインドライブラリ (4)

前回はmaru-dogで標準で提供しているコンバータについて説明しました。maru-dogで提供しているコンバータはすべて拡張コンバータと呼ばれる方式で提供されています。
今回はアルファベット文字列を大文字(もしくは小文字)に変換し、指定されたメッセージを連結して結果を返す独自拡張コンバータの作成方法について説明します。

拡張コンバータを作成するにはまず、コンバートを行いたい項目に対して付与するアノテーションを作成します。

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.maru.dog.converter.ConverterIdentifier;

@Documented
@ConverterIdentifier(ChangeCaseConverter.class)
@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ChangeCase {

    CasePattern casePattern() default CasePattern.UPPER;

    String addedMessage() default "";
}

コンバータアノテーションには必ず@ConverterIdentifierアノテーションを付与し、実際に変換を行うコンバータクラスを定義してください(上記例ではChangeCaseConverter.class)。アノテーション本体ではcasePattern()で大文字小文字の変換を制御するための列挙型と、addedMessage()で連結する文字列を定義しています。

CasePattern列挙型のコードは以下の通りです。

public enum CasePattern {
    UPPER,
    LOWER
}

次に実際にコンバート処理を行うChangeCaseConverter.classを定義します。

import org.maru.common.annotation.Identifier;
import org.maru.common.annotation.Value;
import org.maru.dog.converter.ConverterIdentifier;

public class ChangeCaseConverter {

    @ConverterIdentifier(ChangeCase.class)
    public String changeCase(
            @Value String value,
            @Identifier("casePattern") CasePattern casePattern,
            @Identifier("addedMessage") String addedMessage) {
        value += addedMessage;
        if (casePattern.equals(CasePattern.UPPER)) {
            return value.toUpperCase();
        } else {
            return value.toLowerCase();
        }
    }
}

上記コンバータクラスにはchangeCaseという唯一のメソッドが定義されていますが、このメソッドが@ChangeCaseアノテーションが付与されたプロパティのデータを受け取り変換を行います。当該メソッドにも@ConverterIdentifierアノテーションが付与されています。このアノテーションには先に定義したChangeCaseアノテーションのクラス型が定義されています。
Director内部ではまず入力側のクラスのバインド対象プロパティに@ChangeCaseアノテーションが付与されていると、このアノテーションよりコンバートを行うクラスを@ConverterIdentifier(ChangeCaseConverter.class)より読み取ります。

次にChangeCaseConverterクラスから@ChangeCaseで実行すべきコンバータメソッドを決定します。実行すべきメソッドを識別するための情報が@ConverterIdentifier(ChangeCase.class)です。拡張コンバータではコンバータアノテーションが付与された場合に、そのコンバート処理を行うメソッドに@ConverterIdentifierを付与し、その項目に対象のアノテーションクラスを設定しなければなりません。

コンバータメソッドのパラメータについてですが、変換対象の値を受け取る引数には必ず@Valueを指定する必要があります。コンバータアノテーションより変換処理を行うための深情報を受け取る引数には@Identifierを付与し、受け取るべきアノテーションの項目名をString型で設定しなければなりません。項目名をせってしていない場合はエラーとなります。

上記例では@Valueが付与された引数valueに変換対象データが、@Identifier("casePattern")、@Identifier("addedMessage")が付与された引数casePattern、addedMessageに@ChangeCaseのcasePattern()、addedMessage()の値がそれぞれ渡されてコンバータメソッドが実行され結果が返されます。

返された結果はバインド先の任意の項目にバインドされます。

最後に実行プログラムと実行結果を示します。

import org.maru.dog.Director;
import org.maru.dog.Marudog;
import org.maru.dog.annotation.Bind;
import org.maru.dog.annotation.Bound;

public class Main {

    public static void main(String[] args) {
        TargetBean tbean = new TargetBean();
        InputBean ibean = getInputBean();
        Director director = Marudog.getDirector();
        director.bind(tbean, ibean);
        System.out.println(tbean.message);
    }

    private static InputBean getInputBean() {
        InputBean ibean = new InputBean();
        ibean.message = "test";
        return ibean;
    }

    static class TargetBean {
        @Bound
        String message;
    }

    static class InputBean {
        @Bind
        @ChangeCase(addedMessage = "123")
        String message;
    }
}

上記プログラムの実行結果は"TEST123"です。

InputBeanの小文字の"test"が@ChangeCaseコンバータアノテーションによりcasePatternに従った変換とaddedMessageの"123"という文字列連結が実行され結果がTargetBeanのプロパティにバインドされていることが分かります。

コンバータというと変換処理をイメージしますが、このように、あるデータを任意に加工することも可能です。このような理由から「拡張コンバータ」と名付けました。

最後に拡張コンバータ自体はまだ試行中ですので、定義方法等も含め変更となる可能性があります。(下位互換性がないような変更もあり得るかと・・・)

今回ここまでです。

サイトページ:http://maru.sourceforge.jp/
ドキュメントページ:http://maru.sourceforge.jp/document_dog.html