S2Dxoで文字列と列挙を変換してみる

DB上の区分をそのままシステム上で文字列定数で扱うのはいやだなあと思って、せっかくのSE5.0なので列挙を使ってみる事にした。

最初、Service層で変換かけてやれと思ったんだけど、これまたせっかくなのでDxoでやってしまおうと思いました。

列挙から文字列へはこんな感じでやってみた。

まず列挙。送信フラグ、とかそんなの。

public enum SendFlag {
    NOT_SEND("N"),
    SENDING("S"),
    SENT("E");
    
    private String value;
    
    SendFlag(String value){
        this.value = value;
    }    
    
    public String getValue(){        
        return value;
    }

}

変換対象となるBeanたち。Hogeでは区分を文字列で持つ。HogeDtoで区分を列挙で持つ。

public class Hoge{
    private String sendFlag;
    (setter getter省略)
}

public class HogeDto{
    private SendFlag sendFlag;
    (setter getter省略)
}

で、Dxoアノテーションにこう書いてみた。

@ConversionRule("sendFlag: sendFlag.value)
Hoge convertDtoToEntity(HogeDto src);

見事に変換されましたね。素晴らしいです。

で、今度は逆にHogeからHogeDtoに変換する場合、文字列からなんとかして列挙に変換しないといけません。列挙をこんな風にしてみた。

public enum SendFlag {
    NOT_SEND("N"),
    SENDING("S"),
    SENT("E");
    
    private String value;
    SendFlag(String value){
        this.value = value;
    }    
    
    public String getValue(){        
        return value;
    }
    
    //これを追加
    public static SendFlag getEnumFrom(String str){
        SendFlag[] enums = SendFlag.values();
        for(SendFlag e : enums){
            if(e.equals(str)){
                return e;
            }
        }
        return null;
    }
    //これも追加
    public boolean equals(CharSequence arg){
        if(arg == null){
            return false;
        }
        String str = arg.toString().trim();
        return value.equals(str);
    }
}

これで文字列からクラスメソッドでインスタンスが取れる。さてどうやってアノテーションにかけばいいんだ。なんか出来なさそうなので、独自コンバータを作ってみた。

public class SendFlagConverter extends AbstractConverter {

    public Object convert(Object source, Class destClass,
            ConversionContext context) {
        
        if(source ==null){
            return null;
        }
        
        String srcStr = source.toString();
        return SendFlag.getEnumFrom(srcStr);
    }

    public Class getDestClass() {        
        return SendFlag.class;
    }

    public Class[] getSourceClasses() {
        return new Class[] { Object.class };
    }

}

Dxoのメソッドはこう。

HogeDto convertEntityToDto(Hoge src);

S2コンテナに独自コンバータを登録しないといけません。最初app.diconに書いたんですけど上手い事登録されない。SMART deployではどうやらS2で用意されてるdiconファイルごとにコンテナを生成してるみたいなので、dxo.diconを持ってきてそこに書かないといけないようです。

やってみた。

<components namespace="dxo">
    <component name="interceptor" class="org.seasar.extension.dxo.DxoInterceptor"/>
    
    <component class="org.seasar.extension.dxo.meta.impl.DxoMetadataFactoryImpl"/>
    <component class="org.seasar.extension.dxo.converter.impl.ConverterFactoryImpl"/>
    <component class="org.seasar.extension.dxo.annotation.impl.AnnotationReaderFactoryImpl"/>

    <component class="org.seasar.extension.dxo.builder.impl.MapToBeanDxoCommandBuilder"/>
    <component class="org.seasar.extension.dxo.builder.impl.BeanToMapDxoCommandBuilder"/>
    <component class="org.seasar.extension.dxo.builder.impl.BeanToBeanDxoCommandBuilder"/>
<!-- これを追加 -->
    <component class="jp.co.uchinokaisha.projectname.dxo.impl.SendFlagConverter" />
</components>

なんと!出来たぞー!

うーん、出来たけど、列挙を定義した区分ごとにConverterをつくらねばいけないのがなあと思って、Enumのname()かtoString()をオーバーライドしてそれと比較してマッチした奴を云々とか思ったんですけど、ダメだー、時間がないので区分ごとに作る事にしました。多分そんな数にならないし。

なんかアイデアないかなあ。

Dxoの独自コンバータの使い方、これで合ってるかなあ。

あ、getEnumFrom()の引数がCharSequenceになってるのは、artonさんとるいもさんの『実践Java』の影響で御座居ます。もう手が勝手に。