yohjizzz's Blog

I'm a Programmer.

あれっ?Map のキーが「数字のみ」だと適切にBeanへ変換されない?

S2Dxo を使って、Map から Bean への変換を行う際に Map に「数字のみ」のキーがあると嫌な感じ(↓)になる??

public class HogeDto {
    protected String first; // Getter + Setter。
    protected String second; // Getter + Setter。
    protected String third; // Getter + Setter。
}
public interface HogeDxo {
    @ConversionRule("first : 101, second : 102, third : 103")
    public HogeDto[] convert(Map[] maps); // →こいつが問題!?
    @ConversionRule("101 : first, 102 : second, 103 : third")
    public Map[] convert(HogeDto[] hoges); // →こいつは適切に変換される。
}

んで、、、

    Map map = new HashMap();
    map.put("101", "00000001");
    map.put("102", "00000002");
    map.put("103", "00000003");
    Map[] maps = new Map[] {map};
    
    HogeDto[] hoges = this.hogeDxo.convert(maps);
    
    System.out.println("hogeDxo.getFirst() ---> [" + hoges[0].getFirst() + "].");

そうすると、期待している≪hogeDxo.getFirst() ---> [00000001].≫ではなく、
Map のキーがフィールドにセットされてしまう。≪「hogeDxo.getFirst() ---> [101].」≫。
Bean から Map への変換では問題ないのに…。#ちなみにキーを「数字のみ」から「アルファベット+数字(たとえば"v101")」にすると大丈夫。

なんでっ??
じっくりソース見てる時間もない(もうすぐ結合試験><)ので、とりあえず(Map から Bean へは)違う方法をとることにします。

バージョン古い(v2.4.12)からかな…こんちくしょー><(既にあがってたバグだったりして…)
あとで見てみよ。


≪≪追記(といくつかの訂正)≫≫
id:koichik さんから頂いたコメントをもとにいくつか追記&訂正します。

まず僕は「Map のキー(である"101")が変換対象となってしまってる」という解釈をしている訳ですが、
それは違くて(まぁ違うよね…)、「101」そのものをリテラル定数として扱われてしまっていた為、その値(数値)が変換対象となってしまっていたこと。

んで S2Dxo では変換ルールに OGNL を利用できる。→これはドキュメントにも記載されてます。

なので id:koichik さんがコメントしてくれた方法で対応("101"を Map のキーとしてエントリーの値を取り出してくれる)することが可能でした。
id:koichik さんに感謝。)

ただそこで注意点!
OGNL書式で記述する変換ルールとデフォルト(?)の変換ルール(aaa:bbb)をカンマ区切りで混在させてしまうと、
DxoUtil#addQuote(..) で IllegalArgumentException でコケる><

public interface HogeDxo {
    @ConversionRule("hoge : hogeHoge, 'first' : #this['101'], 'second' : #this['102'], 'third' : #this['103']")
    public HogeDto[] convert(Map[] maps); // →IllegalArgumentException!

このような場合は、、、こう↓しないとだめみたい。
#最新版でどーなるかは試してません。いま使ってるバージョンは「S2(2.4.12)」です。

public interface HogeDxo {
    @ConversionRule("'hoge' : #this['hogeHoge'], 'first' : #this['101'], 'second' : #this['102'], 'third' : #this['103']")
    public HogeDto[] convert(Map[] maps); // →ok!

だったらもう「aaa:bbb」なんて書かないで、常に「'aaa':#this['bbb']」で書こうよって結論に(勝手に)行き着くw
あとややこしいのが、逆パターン(Bean から Map へ)は期待する動作をしていたこと。
左側(変換先)はリテラル(値)だのなんだのってありえないので、「123」をエントリーのキーとして扱ってくれていた訳だ。
う〜ん。なんか優しいような、わかりづらいような・・・。後でちゃんとソースを読みましょう→自分へ。

#たしかに左側(変換先)にリテラル定数を指定することなんてありえない訳だから、
#記述したモノはどんな値(123、'123'、hoge、'hoge')だろうと、
#Bean ならプロパティ、Map ならキーとして扱われるのは、やっぱり優しさだろうか、なんて考えてみたりしました。

id:koichik さん、ありがとうございました。


#おっ! Teeda の 1.0.11-SP1 がリリースされてるぞー○