Jacksonによるマップのシリアライゼーションとデシリアライゼーション

Jacksonでのシリアル化とシリアル化解除のマッピング

1. 概要

この記事では、serialization and deserialization of Java maps using Jacksonについて説明します。

JSON形式のStrings.との間で、Map<String, String>Map<Object, String>,、およびMap<Object, Object>をシリアル化および逆シリアル化する方法を説明します。

2. Mavenの構成


    com.fasterxml.jackson.core
    jackson-databind
    2.9.4

ジャクソンhereの最新バージョンを入手できます。

3. 直列化

シリアル化は、Javaオブジェクトをバイトストリームに変換し、必要に応じて永続化または共有できます。 JavaMapsは、キーObjectを値Objectにマップするコレクションであり、多くの場合、シリアル化するのに最も直感的でないオブジェクトです。

3.1. Map<String, String>シリアル化

単純なケースでは、Map<String, String>を作成し、それをJSONにシリアル化します。

Map map = new HashMap<>();
map.put("key", "value");

ObjectMapper mapper = new ObjectMapper();
String jsonResult = mapper.writerWithDefaultPrettyPrinter()
  .writeValueAsString(map);

ObjectMapperはJacksonのシリアル化マッパーであり、StringtoString()メソッドを使用して、mapをシリアル化し、きれいに印刷されたJSONStringとして書き出すことができます。 s:

{
  "key" : "value"
}

3.2. Map<Object, String>シリアル化

いくつかの追加手順を実行して、カスタムJavaクラスを含むマップをシリアル化できます。 関連するStringオブジェクトのペアを表すMyPairクラスを作成しましょう。

注:ゲッター/セッターはパブリックである必要があり、シリアル化時にJacksonがこのカスタムtoString()を使用するように、toString()@JsonValueの注釈を付けます。

public class MyPair {

    private String first;
    private String second;

    @Override
    @JsonValue
    public String toString() {
        return first + " and " + second;
    }

    // standard getter, setters, equals, hashCode, constructors
}

次に、ジャクソンのJsonSerializerを拡張して、MyPairをシリアル化する方法をジャクソンに伝えましょう。

public class MyPairSerializer extends JsonSerializer {

    private ObjectMapper mapper = new ObjectMapper();

    @Override
    public void serialize(MyPair value,
      JsonGenerator gen,
      SerializerProvider serializers)
      throws IOException, JsonProcessingException {

        StringWriter writer = new StringWriter();
        mapper.writeValue(writer, value);
        gen.writeFieldName(writer.toString());
    }
}

JsonSerializerは、その名前が示すように、MyPairtoString()メソッドを使用してMyPairをJSONにシリアル化します。 Jacksonは、シリアル化の要件に合うように多くのSerializer classesを提供しています。

@JsonSerializeアノテーションを付けてMap<MyPair, String>MyPairSerializerを適用します。 String:をシリアル化する方法をすでに知っているため、MyPairをシリアル化する方法のみをジャクソンに伝えたことに注意してください。

@JsonSerialize(keyUsing = MyPairSerializer.class)
Map map;

マップのシリアル化をテストしてみましょう。

map = new HashMap<>();
MyPair key = new MyPair("Abbott", "Costello");
map.put(key, "Comedy");

String jsonResult = mapper.writerWithDefaultPrettyPrinter()
  .writeValueAsString(map);

シリアル化されたJSON出力は次のとおりです。

{
  "Abbott and Costello" : "Comedy"
}

3.3. Map<Object, Object>シリアル化

最も複雑なケースはMap<Object, Object>のシリアル化ですが、ほとんどの作業はすでに完了しています。 マップにはジャクソンのMapSerializerを使用し、マップのキーと値のタイプには前のセクションのMyPairSerializerを使用しましょう。

@JsonSerialize(keyUsing = MapSerializer.class)
Map map;

@JsonSerialize(keyUsing = MyPairSerializer.class)
MyPair mapKey;

@JsonSerialize(keyUsing = MyPairSerializer.class)
MyPair mapValue;

Map<MyPair, MyPair>のシリアル化をテストしてみましょう。

mapKey = new MyPair("Abbott", "Costello");
mapValue = new MyPair("Comedy", "1940s");
map.put(mapKey, mapValue);

String jsonResult = mapper.writerWithDefaultPrettyPrinter()
  .writeValueAsString(map);

MyPairtoString()メソッドを使用したシリアル化されたJSON出力は次のとおりです。

{
  "Abbott and Costello" : "Comedy and 1940s"
}

4. 逆シリアル化

逆シリアル化は、バイトストリームをコードで使用できるJavaオブジェクトに変換します。 このセクションでは、JSON入力をさまざまな署名のMapsに逆シリアル化します。

4.1. Map<String, String>デシリアライズ

単純なケースでは、JSON形式の入力文字列を取得してMap<String, String>Javaコレクションに変換してみましょう。

String jsonInput = "{\"key\": \"value\"}";
TypeReference> typeRef
  = new TypeReference>() {};
Map map = mapper.readValue(jsonInput, typeRef);

シリアル化の場合と同じようにJacksonのObjectMapperを使用し、readValue()を使用して入力を処理します。 また、すべての逆シリアル化の例で使用するJacksonのTypeReferenceを使用して、宛先Mapのタイプを説明していることに注意してください。 マップのtoString()表現は次のとおりです。

{key=value}

4.2. Map<Object, String>デシリアライズ

次に、入力JSONと宛先のTypeReferenceMap<MyPair, String>に変更しましょう。

String jsonInput = "{\"Abbott and Costello\" : \"Comedy\"}";

TypeReference> typeRef
  = new TypeReference>() {};
Map map = mapper.readValue(jsonInput, typeRef);

両方の要素を持つStringを受け取り、それらをMyPair要素に解析するMyPairのコンストラクターを作成する必要があります。

public MyPair(String both) {
    String[] pairs = both.split("and");
    this.first = pairs[0].trim();
    this.second = pairs[1].trim();
}

そして、Map<MyPair,String>オブジェクトのtoString()は次のとおりです。

{Abbott and Costello=Comedy}

There is another option for the case when we deserialize into a Java class that contains a Map — we can use Jackson’s KeyDeserializer class、ジャクソンが提供する多くのDeserializationクラスの1つ。 ClassWithAMap@JsonCreator@JsonProperty、および@JsonDeserialize:の注釈を付けます

public class ClassWithAMap {

  @JsonProperty("map")
  @JsonDeserialize(keyUsing = MyPairDeserializer.class)
  private Map map;

  @JsonCreator
  public ClassWithAMap(Map map) {
    this.map = map;
  }

  // public getters/setters omitted
}

ClassWithAMapに含まれるMap<MyPair, String>を逆シリアル化するようにジャクソンに指示しているので、入力からマップのキーであるMyPairオブジェクトを逆シリアル化する方法を説明するためにKeyDeserializerを拡張する必要がありますString

public class MyPairDeserializer extends KeyDeserializer {

  @Override
  public MyPair deserializeKey(
    String key,
    DeserializationContext ctxt) throws IOException,
    JsonProcessingException {

      return new MyPair(key);
    }
}

readValueを使用して逆シリアル化をテストします。

String jsonInput = "{\"Abbott and Costello\":\"Comedy\"}";

ClassWithAMap classWithMap = mapper.readValue(jsonInput,
  ClassWithAMap.class);

繰り返しますが、ClassWithAMap’sマップのtoString()メソッドは、期待する出力を提供します。

{Abbott and Costello=Comedy}

4.3. Map<Object,Object>デシリアライズ

最後に、入力JSONと宛先のTypeReferenceMap<MyPair, MyPair>に変更しましょう。

String jsonInput = "{\"Abbott and Costello\" : \"Comedy and 1940s\"}";
TypeReference> typeRef
  = new TypeReference>() {};
Map map = mapper.readValue(jsonInput, typeRef);

そして、Map<MyPair, MyPair>オブジェクトのtoString()は次のとおりです。

{Abbott and Costello=Comedy and 1940s}

5. 結論

このクイックチュートリアルでは、JavaMapsをJSON形式の文字列との間でシリアル化および逆シリアル化する方法を説明しました。

いつものように、この記事で提供されている例をGithub repositoryで確認できます。