Map Serialization and Deserialization with Jackson

1. Overview

In this article, we'll look at serialization and deserialization of Java maps using Jackson.

We'll illustrate how to serialize and deserialize Map<String, String>, Map<Object, String>, and Map<Object, Object> _to and from JSON-formatted _Strings.

2. Maven Configuration

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.8.7</version>
</dependency>

You can get the latest version of Jackson here.

3. Serialization

Serialization converts a Java object into a stream of bytes, which can be persisted or shared as needed. Java Maps are collections which map a key Object to a value Object and are often the least intuitive objects to serialize.

3.1. Map<String, String> Serialization

For the simple case, let's create a Map<String, String> and serialize it to JSON:

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

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

ObjectMapper _is Jackson's serialization mapper, which allows us to serialize our _map and write it out as a pretty-printed JSON String, using the toString() method in String:

{
  "key" : "value"
}

3.2. Map<Object, String> Serialization

You can serialize a map containing a custom Java class with a few extra steps. Let's create a MyPair class to represent a pair of related String objects.

Note: the getters/setters should be public, and we annotate toString() _with @JsonValue to ensure Jackson uses this custom _toString() when serializing:

public class MyPair {

    private String first;
    private String second;

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

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

Now let's tell Jackson how to serialize MyPair by extending Jackson's JsonSerializer:

public class MyPairSerializer extends JsonSerializer<MyPair> {

    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, as the name suggests, serializes MyPair to JSON using MyPair's toString() method. Jackson provides many Serializer classes to fit your serialization requirements.

We apply MyPairSerializer to our Map<MyPair, String> with the @JsonSerialize_annotation. Note that we've only told Jackson how to serialize _MyPair _because it already knows how to serialize _String:

@JsonSerialize(keyUsing = MyPairSerializer.class) 
Map<MyPair, String> map;

Let's test our map serialization:

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

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

The serialized JSON output is:

{
  "Abbott and Costello" : "Comedy"
}

3.3. Map<Object, Object> Serialization

The most complex case is serializing a Map<Object, Object>, but most of the work is already done. Let's use Jackson's _MapSerializer _for our map, and _MyPairSerializer_from the previous section for the map's key and value types:

@JsonSerialize(keyUsing = MapSerializer.class)
Map<MyPair, MyPair> map;

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

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

Let's test out serializing our Map<MyPair, MyPair>:

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

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

The serialized JSON output, using MyPair's toString() method, is:

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

4. Deserialization

Deserialization converts a stream of bytes into a Java object that we can use in code. In this section, we'll deserialize JSON input into _Maps _of different signatures.

4.1. Map<String, String> Deserialization

For the simple case, let's take a JSON-formatted input string and convert it to a Map<String, String> Java collection:

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

We use Jackson's ObjectMapper as we did for serialization, using readValue() _to process the input. Also, note our use of Jackson's _TypeReference, which we'll use in all of our deserialization examples, to describe the type of our destination Map. Here is the _toString() _representation of our map:

{key=value}

4.2. Map<Object, String> Deserialization

Now, let's change our input JSON and the TypeReference _of our destination to_Map<MyPair, String>:

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

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

We need to create a constructor for MyPair that takes a String with both elements and parses them to the MyPair elements:

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

And the toString() of our Map<MyPair,String> object is:

{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 , one of many Deserialization classes that Jackson offers. We annotate our ClassWithAMap with @JsonCreator, @JsonProperty, and @JsonDeserialize:

public class ClassWithAMap {

  @JsonProperty("map")
  @JsonDeserialize(keyUsing = MyPairDeserializer.class)
  private Map<MyPair, String> map;

  @JsonCreator
  public ClassWithAMap(Map<MyPair, String> map) {
    this.map = map;
  }

  // public getters/setters omitted
}

We are telling Jackson to deserialize the Map<MyPair, String> _contained in _ClassWithAMap, so we need to extend KeyDeserializer _to describe how to deserialize the map's key, a _MyPair _object, from an input _String:

public class MyPairDeserializer extends KeyDeserializer {

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

      return new MyPair(key);
    }
}

We test the deserialization out using readValue:

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

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

Again, the toString() method of our ClassWithAMap's map gives us the output we expect:

{Abbott and Costello=Comedy}

4.3. Map<Object,Object> Deserialization

Lastly, let's change our input JSON and the TypeReference of our destination to Map<MyPair, MyPair>:

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

And the toString() of our Map<MyPair, MyPair> object is:

{Abbott and Costello=Comedy and 1940s}

5. Conclusion

In this quick tutorial, we've seen how to serialize and deserialize Java Maps to and from JSON-formatted Strings.

As always, you can check out the example provided in this article in the Github repository.

原文链接:http://www.baeldung.com/jackson-map

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值