spring.svg

【Spring Boot】JacksonによるJSON変換

SpringBoot

Jackson とは

Spring Boot における REST API では、戻り値に設定したクラスのインスタンスを JSON に変換してレスポンスを返します。 また、リクエストボディの JSON は、@RequestBodyを付与することで引数に設定したクラスのインスタンスに変換します。

インスタンスから JSON へ変換することを「シリアライズ」、JSON からインスタンスへ変換することを「デシリアライズ」といいます。

@RestController
public class SampleController {
  //SampleDataをJSONに変換して返す
  @GetMapping
  public SampleData get() {
    return new SampleData();
  }

  //JSONデータを受け取り、SampleDataに変換する
  @PostMapping
  public void post(@RequestBody SampleData sampleData) {
    //...
  }
}

これらの JSON の変換は、Jackson というライブラリによって行われており、Spring Boot では標準で搭載されています。 この Jackson について知ることにより、より柔軟に JSON を扱うことができるようになります。

プロパティの変更

@JsonProperty

対応するプロパティ名を変更します。 これはシリアライズ、デシリアライズともに適用されます。

public class SampleData {
  private String id;

  @JsonProperty("first_name")
  private String firstName;

  @JsonProperty("last_name")
  private String lastName;
}
JSON
{
  "id": "0001",
  "first_name": "Taro",
  "last_name": "Yamada"
}

@JsonPropertyOrder

シリアライズした JSON のプロパティの出力順を設定します。

@JsonPropertyOrder({"firstName", "lastName", "id"})
public class SampleData {
  private String id;
  private String firstName;
  private String lastName;
}
JSON
{
  "first_name": "Taro",
  "last_name": "Yamada",
  "id": "0001"
}

プロパティの除外

@JsonIgnore

指定したプロパティをシリアライズ、デシリアライズの対象外とします。

public class SampleData {
  private String id;

  @JsonIgnore
  private String firstName;

  private String lastName;
}
JSON
{
  "id": "0001",
  "lastName": "Yamada"
}

@JsonIgnoreProperties

@JsonIgnoreを一括で設定します。

@JsonIgnoreProperties({"firstName", "lastName"})
public class SampleData {
  private String id;
  private String firstName;
  private String lastName;
}
JSON
{
  "id": "0001"
}

@JsonInclude

シリアライズで対象外にするプロパティの条件を設定します。 設定できる条件には、以下のようなものがあります。

条件説明
Include.NON_NULLnullの場合に対象外とする
Include.NON_EMPTY空文字の場合に対象外とする
Include.NON_DEFAULTデフォルト値の場合に対象外とする
  • NON_NULL
    @JsonInclude(Include.NON_NULL)
    public class SampleData {
      private String id;
      private String firstName;
      private String lastName;
    }
    new SampleData("0001", null, "Yamada");
    JSON
    {
      "id": "0001",
      "lastName": "Yamada"
    }
  • NON_EMPTY
    @JsonInclude(Include.NON_EMPTY)
    public class SampleData {
      private String id;
      private String firstName;
      private String lastName;
    }
    new SampleData("0001", "", "Yamada");
    JSON
    {
      "id": "0001",
      "lastName": "Yamada"
    }
  • NON_DEFAULT
    @JsonInclude(Include.NON_DEFAULT)
    public class SampleData {
      private String id = "";
      private String firstName = "Taro";
      private String lastName = "";
    }
    new SampleData("0001", "Taro", "Yamada");
    JSON
    {
      "id": "0001",
      "lastName": "Yamada"
    }

例ではクラスに付与していますが、フィールド単位でも設定できます。

プロパティの出力・設定

@JsonGetter

シリアライズに使用するゲッターを、別のメソッドに変更します。

public class SampleData {
  private String id;
  private String firstName;
  private String lastName;

  @JsonGetter("firstName")
  public String getTheFirstName() {
    return fristName;
  }
}

@JsonSetter

デシリアライズに使用するセッターを、別のメソッドに変更します。

public class SampleData {
  private String id;
  private String firstName;
  private String lastName;

  @JsonSetter("firstName")
  public void setTheFirstName(String firstName) {
    this.firstName = firstName;
  }
}

@JsonAnyGetter

Mapのゲッターに付与することで、階層を無視してシリアライズします。

public class SampleData {
  private String id;
  private Map<String, String> name;

  @JsonAnyGetter
  public Map<String, String> getName() {
    return name;
  }
}
@JsonAnyGetterなし
{
  "id": "0001",
  "name": {
    "firstName": "Taro",
    "lastName": "Yamada"
  }
}
@JsonAnyGetterあり
{
  "id": "0001",
  "first_name": "Taro",
  "last_name": "Yamada"
}

@JsonFormat

シリアライズ、デシリアライズの型とフォーマットパターンを設定します。

public class SampleData {
  @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy/MM/dd HH:mm:ss")
  private Date date;
}
JSON
{
  "date": "2021/05/01 12:34:56"
}

変換

@JsonValue

シリアライズの処理を指定します。

public class SampleData {
  private String id;
  private String firstName;
  private String lastName;

  @JsonValue
  public Map<String, Object> toJson() {
    Map<String, Object> map = new LinkedHashMap<>();
    map.put("id", id);
    map.put("name", firstName + lastName);
    return map;
  }
}
JSON
{
  "id": "0001",
  "name": "TaroYamada"
}

@JsonCreator

デシリアライズの処理(コンストラクタ)を指定します。

public class SampleData {
  private String id;
  private String name;

  @JsonCreator
  public SampleData(String id, String firstName, String lastName) {
    this.id = id;
    this.name = firstName + lastName;
  }
}
JSON
{
  "id": "0001",
  "firstName": "Taro",
  "lastName": "Yamada"
}

列挙型の JSON 化

列挙型をシリアライズするには、@JsonValueを使用します。

public enum EnumSample {
  STATE1(1, "0001"),
  STATE2(2, "0002");

  private int id;
  private String name;

  private EnumSample(int code, String name) {
    this.id = id;
    this.name = name;
  }

  @JsonValue
  public Map<String, Object> toJson() {
    Map<String, Object> map = new LinkedHashMap<>();
    map.put("id", id);
    map.put("name", name);
    return map;
  }
}
JSON
{
  "id": 1,
  "name": "0001"
}

また、@JsonFormatを使用しても同じ結果が得られます。

@JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum EnumSample {
  STATE1(1, "0001"),
  STATE2(2, "0002");

  private int id;
  private String name;

  private EnumSample(int code, String name) {
    this.id = id;
    this.name = name;
  }
}