まめログ

Javaプログラマの歩み

Javaのジェネリクスのワイルドカードが便利だった

複数の階層構造を表すJSON形式の文字列を一つの処理でクライアントに返す必要があった時に、
少し詰まったのでメモとして。
JSONへの変換にはGsonを使いました。

以下のような構造が異なる二つのクラスを、
一回の処理でJSON形式の文字列にする方法を考えたときに、
ワイルドカードで書くことでうまくできました。

/**
 * モーニング娘。のメンバー
 */
public class MorningMusumeMember implements HelloProject{

    private String generation;
    private String name;
    private String yomi;

    public MorningMusumeMember(String generation,String name,String yomi){
        this.generation = generation;
        this.name = name;
        this.yomi = yomi;
    }
}

モーニング娘。は、何期加入かと名前と読み仮名を保持するようにしておきます。

/**
 * Berryz工房のメンバー
 * @author ta
 *
 */
public class BerryzKoboMember implements HelloProject{

    private String name;
    private String yomi;

    public BerryzKoboMember(String name,String yomi){
        this.name = name;
        this.yomi = yomi;
    }
}

Berryz工房には、1期2期といった概念がないので、名前と読み仮名だけにしておきます。

GsonにするオブジェクトはMapで以下のように宣言しておきます。

    Map<String,List<? extends HelloProject>> map = new HashMap<String, List<? extends HelloProject>>();

Mapにそれぞれのインスタンスを格納する処理は以下のようなコードです。
?の後にextendsでクラスを指定するとワイルドカードに上限を設定することが出来ます。
この場合、HelloProjectでないメンバーのリストを追加できないことになります。

    List<MorningMusumeMember> morningMembers = getMoringMusumeMembers();
    map.put("モーニング娘。", morningMembers);
    List<BerryzKoboMember> berryzMembers = getBerryzKoboMembers();
    map.put("Berryz工房", berryzMembers);
    
    map.put("AKB48",akb48Members); //コンパイルエラー

あとはGsonでJSON形式に変換するだけです。
setPrettyPrinting()を入れておくと、項目ごとに改行が入って見やすくなります。

   Gson gson = new GsonBuilder().setPrettyPrinting().create();
   System.out.println(gson.toJson(map));

出力結果はこんな感じ。

{
  "Berryz工房": [
    {
      "name": "嗣永桃子",
      "yomi": "つぐながももこ"
    },
    {
      "name": "夏焼雅",
      "yomi": "なつやきみやび"
    },
    {
      "name": "熊井友理奈",
      "yomi": "くまいゆりな"
    },
    {
      "name": "清水佐紀",
      "yomi": "しみずさき"
    },
    {
      "name": "徳永千奈美",
      "yomi": "とくながちなみ"
    },
    {
      "name": "須藤茉麻",
      "yomi": "すどうまあさ"
    }
  ],
  "モーニング娘。": [
    {
      "generation": "9期",
      "name": "鞘師里保",
      "yomi": "さやしりほ"
    },
    {
      "generation": "9期",
      "name": "譜久村聖",
      "yomi": "ふくむらみずき"
    },
    {
      "generation": "9期",
      "name": "鈴木香音",
      "yomi": "すずきかのん"
    },
    {
      "generation": "9期",
      "name": "生田衣梨奈",
      "yomi": "いくたえりな"
    },
    {
      "generation": "10期",
      "name": "飯窪春奈",
      "yomi": "いいくぼはるな"
    },
    {
      "generation": "10期",
      "name": "石田亜佑美",
      "yomi": "いしだあゆみ"
    },
    {
      "generation": "10期",
      "name": "工藤遥",
      "yomi": "くどうはるか"
    },
    {
      "generation": "10期",
      "name": "佐藤優樹",
      "yomi": "さとうまさき"
    },
    {
      "generation": "11期",
      "name": "小田さくら",
      "yomi": "おださくら"
    },
    {
      "generation": "12期",
      "name": "尾形春水",
      "yomi": "おがたはるな"
    },
    {
      "generation": "12期",
      "name": "野中美希",
      "yomi": "のなかみき"
    },
    {
      "generation": "12期",
      "name": "牧野真莉愛",
      "yomi": "まきのまりあ"
    },
    {
      "generation": "12期",
      "name": "羽賀朱音",
      "yomi": "はがあかね"
    }
  ]
}

僕は、鞘師里保ちゃんが好きです。