ジェネリクスを使ってJacksonで取得したオブジェクト型を可変化する

ジェネリクスを使ってJacksonで取得したオブジェクト型を可変化する

JacksonはJson形式の文字列をオブジェクト化するJavaライブラリです。

Jsonの内容に合わせてJavaクラスをそれぞれ作成し、変換時に該当するクラスを指定することでオブジェクト化できます。

ただ実際のプロジェクトでは変換後のクラスごとに変換メソッドを別々に作るような悲しい状態が見受けられます。

Javaにはジェネリクスという便利なものがあります。

今回はメソッドの戻り値にジェネリクスを使用することでJacksonで変換するメソッドを共通化します。

ジェネリクスなしでJacksonで変換するメソッドをそれぞれで作る

まずはジェネリクスを使用しない単純なJacksonで変換するメソッドを作ります。

例としてJsonの形式をチーム情報、選手情報の2種類用意し、クラスはTeam、Playerとします。

Jacksonで変換されたものを受け取るクラスを作成

Team.java(チーム情報)

package test;

import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;

import lombok.Data;

/**
 * チーム情報
 */
@Data
public class Team {

    @JsonProperty(value = "id")
    String id;

    @JsonProperty(value = "name")
    String name;
}

Player.java(選手情報)

package test;


import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;

import lombok.Data;

/**
 * 選手情報
 */
@Data
public class Player {

    @JsonProperty(value = "id")
    String id;

    @JsonProperty(value = "name")
    String name;

    @JsonProperty(value = "position")
    String position;

    @JsonProperty(value = "teamId")
    String teamId;
}

Jacksonで変換するメソッドを作成

上記2クラスに変換するメソッドをそれぞれ作ります。

JacksonUtil.java

package test1;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException
import com.fasterxml.jackson.databind.ObjectMapper;

public class JacksonUtil {

    public static Team getTeam(String json) {

        ObjectMapper mapper = new ObjectMapper();

        try {
           return mapper.readValue(jsonData, Team.class);
        } catch (JsonParseException e) {
            e.printStackTrace();
        } catch (JsonMappingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static Player getPlayer(String json) {

        ObjectMapper mapper = new ObjectMapper();

        try {
           return mapper.readValue(jsonData, Player.class);
        } catch (JsonParseException e) {
            e.printStackTrace();
        } catch (JsonMappingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

ご覧の通り2つのメソッドの相違点はクラス指定(Team.class、Player.class)の1箇所のみです。

これはよろしくないですね。

呼び出し側を作成

呼び出し側を作成します。

Test.java


package test;

public class Test {

    public static void main(String[] args) {

        String jsonTeam = "{\"id\":\"1\",\"name\":\"ヤクルトスワローズ\"}";
        String jsonPlayer = "{\"id\":\"1\",\"name\":\"村上宗隆\",\"position\":\"三塁手\",\"teamId\":\"1\"}";

        Team team = JacksonUtil.getTeam(jsonTeam);
        Player player = JacksonUtil.getPlayer(jsonPlayer);
    }
}

それぞれのメソッドを呼んでます。

ジェネリクスを使ったメソッドに修正する

それではメソッドの戻り値をジェネリクス指定したものに修正します。

受け取るクラスはそのままですが取得する部分を変更します。

ジェネリクスありに変更したメソッド

ジェネリクスを使用することでメソッドを一つにします。

JacksonUtil.java

package test1;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException
import com.fasterxml.jackson.databind.ObjectMapper;

public class JacksonUtil {

    public static <T> T getJackson(String json, Class<T> clazz) {

        ObjectMapper mapper = new ObjectMapper();

        try {
           return mapper.readValue(jsonData, clazz);
        } catch (JsonParseException e) {
            e.printStackTrace();
        } catch (JsonMappingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

getJacksonというメソッドひとつにしました。

変更点は次のとおり

  • メソッドの戻り値定義のところで<T> Tとする
  • 引数にclazzを追加してmapper.readValueに渡すクラスの引数を呼び出し側で指定できるようにする。

ジェネリクスのクラスについては”T”じゃなくても問題ありません。

呼び出し方を変更

呼び出す部分は次のようになります。

package test;

public class Test {

    public static void main(String[] args) {

        String jsonTeam = "{\"id\":\"1\",\"name\":\"ヤクルトスワローズ\"}";
        String jsonPlayer = "{\"id\":\"1\",\"name\":\"村上宗隆\",\"position\":\"三塁手\",\"teamId\":\"1\"}";

        Team team = JacksonUtil.getJackson(jsonTeam, Team.class);
        Player player = JacksonUtil.getJackson(jsonPlayer, Player.class);
    }
}

getJacksonメソッド呼び出し時にクラス引数を指定しています。

リスト変換に対応する

上記では1レコードずつの変換のみ対応していますが、当然リストでの変換も必要になります。

ただそのときもリストに対応した受け取りクラスを作成するのみで完結します。

Jackson変換メソッドはそのままで大丈夫です。

リスト対応したクラスを作成

作成済みのクラスをリスト保持するものを作ればOKです。

Teams.java

package test;

import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;

import lombok.Data;

/**
 * チームリスト
 */
@Data
public class Teams {

    @JsonProperty(value = "teams")
    List<Team> teams;
}

呼び出し方は変わりません。

package test;

public class Test {

    public static void main(String[] args) {

        String jsonTeams = "{\"teams\":[{\"id\":\"1\",\"name\":\"ヤクルトスワローズ\"},{\"id\":\"2\",\"name\":\"横浜Denaベイスターズ\"},{\"id\":\"3\",\"name\":\"阪神タイガース\"}]}";

        Teams teams = JacksonUtil.getJackson(jsonTeam, Teams.class);
    }
}

この辺りはJsonに合わせてクラスを作っていく感じでいいかと思います。

カテゴリー

yakionigiri

yakionigiri

40代プログラマ。

長いあいだ同じ取引先で仕事をしていたため新技術の勉強を怠る。

最近ようやく焦り始めたのかLaravelやVue.jsを学び始めた。

(身についてはいない)