Сериализация и десериализация карты с Джексоном

Сериализация и десериализация карты с Джексоном

1. обзор

В этой статье мы рассмотримserialization and deserialization of Java maps using Jackson.

Мы проиллюстрируем, как сериализовать и десериализоватьMap<String, String>,Map<Object, String>, иMap<Object, Object> в и из JSON-форматированныхStrings..

2. Конфигурация Maven


    com.fasterxml.jackson.core
    jackson-databind
    2.9.4

Вы можете получить последнюю версию Jacksonhere.

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 - это преобразователь сериализации Джексона, который позволяет нам сериализовать нашmap и записать его как красиво напечатанный JSONString, используя методtoString() вString:

{
  "key" : "value"
}

3.2. Map<Object, String> Сериализация

Вы можете сериализовать карту, содержащую пользовательский класс Java, с помощью нескольких дополнительных шагов. Давайте создадим классMyPair для представления пары связанных объектовString.

Примечание: геттеры / сеттеры должны быть общедоступными, и мы аннотируемtoString() с помощью@JsonValue, чтобы гарантировать, что Джексон использует этот пользовательскийtoString() при сериализации:

public class MyPair {

    private String first;
    private String second;

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

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

Теперь давайте расскажем Джексону, как сериализоватьMyPair, расширивJsonSerializer Джексона:

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, как следует из названия, сериализуетMyPair в JSON, используя методMyPair ’stoString(). Джексон предоставляет множествоSerializer classesдля соответствия вашим требованиям сериализации.

Мы применяемMyPairSerializer к нашемуMap<MyPair, String> с аннотацией@JsonSerialize. Обратите внимание, что мы сказали Джексону, как сериализоватьMyPair, потому что он уже знает, как сериализоватьString:.

@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);

Сериализованный вывод JSON с использованием методаMyPair ’stoString():

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

4. Десериализация

Десериализация преобразует поток байтов в объект Java, который мы можем использовать в коде. В этом разделе мы десериализуем ввод JSON вMaps различных сигнатур.

4.1. Map<String, String> Десериализация

В простом случае возьмем входную строку в формате JSON и преобразуем ее в коллекцию JavaMap<String, String>:

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

Мы используемObjectMapper Джексона, как и для сериализации, используяreadValue() для обработки ввода. Также обратите внимание на то, что мы используемTypeReference Джексона, который мы будем использовать во всех наших примерах десериализации, чтобы описать тип нашего пункта назначенияMap. Вот представлениеtoString() нашей карты:

{key=value}

4.2. Map<Object, String> Десериализация

Теперь давайте изменим наш входной JSON иTypeReference нашего пункта назначения наMap<MyPair, String>:

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

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

Нам нужно создать конструктор дляMyPair, который беретString с обоими элементами и анализирует их на элементыMyPair:

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

ИtoString() нашего объектаMap<MyPair,String>:

{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, которые предлагает Джексон. Мы аннотируем наш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
}

Мы говорим Джексону десериализоватьMap<MyPair, String>, содержащиеся вClassWithAMap, поэтому нам нужно расширитьKeyDeserializer, чтобы описать, как десериализовать ключ карты, объектMyPair, из входных данных. 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);

Опять же, методtoString() нашей картыClassWithAMap’s дает нам ожидаемый результат:

{Abbott and Costello=Comedy}

4.3. Map<Object,Object> Десериализация

Наконец, давайте изменим наш входной JSON иTypeReference нашего пункта назначения наMap<MyPair, MyPair>:

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

ИtoString() нашего объектаMap<MyPair, MyPair>:

{Abbott and Costello=Comedy and 1940s}

5. Заключение

В этом кратком руководстве мы увидели, как сериализовать и десериализовать JavaMaps в строки в формате JSON и обратно.

Как всегда, вы можете ознакомиться с примером из этой статьи вGithub repository.