Map Serialization and Deserialization with Jackson

向右看齐 2022-06-13 11:26 203阅读 0赞

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, Map, and Map _to and from JSON-formatted _Strings.

2. Maven Configuration

  1. <dependency>
  2. <groupId>com.fasterxml.jackson.core</groupId>
  3. <artifactId>jackson-databind</artifactId>
  4. <version>2.8.7</version>
  5. </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 Serialization

For the simple case, let’s create a Map and serialize it to JSON:

  1. Map<String, String> map = new HashMap<>();
  2. map.put("key", "value");
  3. ObjectMapper mapper = new ObjectMapper();
  4. String jsonResult = mapper.writerWithDefaultPrettyPrinter()
  5. .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:

  1. {
  2. "key" : "value" }

3.2. Map 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:

  1. public class MyPair {
  2. private String first;
  3. private String second;
  4. @Override
  5. @JsonValue
  6. public String toString() {
  7. return first + " and " + second;
  8. }
  9. // standard getter, setters, equals, hashCode, constructors
  10. }

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

  1. public class MyPairSerializer extends JsonSerializer<MyPair> {
  2. private ObjectMapper mapper = new ObjectMapper();
  3. @Override
  4. public void serialize(MyPair value,
  5. JsonGenerator gen,
  6. SerializerProvider serializers)
  7. throws IOException, JsonProcessingException {
  8. StringWriter writer = new StringWriter();
  9. mapper.writeValue(writer, value);
  10. gen.writeFieldName(writer.toString());
  11. }
  12. }

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 with the @JsonSerialize_annotation. Note that we’ve only told Jackson how to serialize _MyPair _because it already knows how to serialize _String:

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

Let’s test our map serialization:

  1. map = new HashMap<>();
  2. MyPair key = new MyPair("Abbott", "Costello");
  3. map.put(key, "Comedy");
  4. String jsonResult = mapper.writerWithDefaultPrettyPrinter()
  5. .writeValueAsString(map);

The serialized JSON output is:

  1. {
  2. "Abbott and Costello" : "Comedy" }

3.3. Map Serialization

The most complex case is serializing a Map, 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:

  1. @JsonSerialize(keyUsing = MapSerializer.class)
  2. Map<MyPair, MyPair> map;
  3. @JsonSerialize(keyUsing = MyPairSerializer.class)
  4. MyPair mapKey;
  5. @JsonSerialize(keyUsing = MyPairSerializer.class)
  6. MyPair mapValue;

Let’s test out serializing our Map:

  1. mapKey = new MyPair("Abbott", "Costello");
  2. mapValue = new MyPair("Comedy", "1940s");
  3. map.put(mapKey, mapValue);
  4. String jsonResult = mapper.writerWithDefaultPrettyPrinter()
  5. .writeValueAsString(map);

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

  1. {
  2. "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 Deserialization

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

  1. String jsonInput = "{\"key\": \"value\"}";
  2. TypeReference<HashMap<String, String>> typeRef
  3. = new TypeReference<HashMap<String, String>>() {};
  4. 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:

  1. {key=value}

4.2. Map Deserialization

Now, let’s change our input JSON and the TypeReference _of our destination to_Map:

  1. String jsonInput = "{\"Abbott and Costello\" : \"Comedy\"}";
  2. TypeReference<HashMap<MyPair, String>> typeRef
  3. = new TypeReference<HashMap<MyPair, String>>() {};
  4. 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:

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

And the toString() of our Map object is:

  1. {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:

  1. public class ClassWithAMap {
  2. @JsonProperty("map")
  3. @JsonDeserialize(keyUsing = MyPairDeserializer.class)
  4. private Map<MyPair, String> map;
  5. @JsonCreator
  6. public ClassWithAMap(Map<MyPair, String> map) {
  7. this.map = map;
  8. }
  9. // public getters/setters omitted
  10. }

We are telling Jackson to deserialize the Map _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:

  1. public class MyPairDeserializer extends KeyDeserializer {
  2. @Override
  3. public MyPair deserializeKey(
  4. String key,
  5. DeserializationContext ctxt) throws IOException,
  6. JsonProcessingException {
  7. return new MyPair(key);
  8. }
  9. }

We test the deserialization out using readValue:

  1. String jsonInput = "{\"Abbott and Costello\":\"Comedy\"}";
  2. ClassWithAMap classWithMap = mapper.readValue(jsonInput,
  3. ClassWithAMap.class);

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

  1. {Abbott and Costello=Comedy}

4.3. Map Deserialization

Lastly, let’s change our input JSON and the TypeReference of our destination to Map:

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

And the toString() of our Map object is:

  1. {
  2. 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

发表评论

表情:
评论列表 (有 0 条评论,203人围观)

还没有评论,来说两句吧...

相关阅读