1. Обзор
В этом кратком руководстве мы рассмотрим сериализацию и десериализацию карт Java с помощью Jackson .
Мы покажем, как сериализовать и десериализовать Map<String, String>
, Map<Object, String>
и Map<Object, Object> в
строки
в формате JSON и обратно . ``
2. Конфигурация Maven
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.11.1</version>
</dependency>
Мы можем получить последнюю версию Джексона здесь .
3. Сериализация
Сериализация преобразует объект Java в поток байтов, который можно сохранять или совместно использовать по мере необходимости. Карты
Java — это коллекции, которые сопоставляют ключевой объект объекту
значения
и часто являются наименее интуитивными объектами для сериализации.
3.1. Map<String, String>
Сериализация
Для простого случая давайте создадим Map<String, String>
и сериализуем его в JSON:
Map<String, String> map = new HashMap<>();
map.put("key", "value");
ObjectMapper mapper = new ObjectMapper();
String jsonResult = mapper.writerWithDefaultPrettyPrinter()
.writeValueAsString(map);
ObjectMapper
— это преобразователь сериализации Джексона. Это позволяет нам сериализовать нашу карту
и записать ее в виде красиво напечатанной строки
JSON , используя метод 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<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
, как следует из названия, сериализует MyPair
в JSON, используя метод toString()
MyPair
. Кроме того, Джексон предоставляет множество классов Serializer , соответствующих нашим требованиям к сериализации. ``
Затем мы применяем MyPairSerializer
к нашей карте Map<MyPair, String>
с аннотацией @JsonSerialize
. Обратите внимание, что мы рассказали Джексону, как сериализовать MyPair
, только потому, что он уже знает, как сериализовать String:
@JsonSerialize(keyUsing = MyPairSerializer.class)
Map<MyPair, String> 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<MyPair, MyPair> 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
toString()
:
{
"Abbott and Costello" : "Comedy and 1940s"
}
4. Десериализация
Десериализация преобразует поток байтов в объект Java, который мы можем использовать в коде. В этом разделе мы десериализуем ввод JSON в Map
с
разными подписями.
4.1. Map<String, String>
Десериализация
Для простого случая возьмем входную строку в формате JSON и преобразуем ее в коллекцию Map<String, String>
Java:
String jsonInput = "{\"key\": \"value\"}";
TypeReference<HashMap<String, String>> typeRef
= new TypeReference<HashMap<String, String>>() {};
Map<String, String> 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<HashMap<MyPair, String>> typeRef
= new TypeReference<HashMap<MyPair, String>>() {};
Map<MyPair,String> 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}
Есть еще один вариант, когда мы десериализуем в класс Java, содержащий Map;
мы можем использовать класс KeyDeserializer
Джексона , один из многих классов десериализации , которые предлагает Джексон. Давайте аннотируем наш ClassWithAMap
с помощью @JsonCreator
, @JsonProperty
и @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
}
Здесь мы говорим Джексону десериализовать 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
дает нам ожидаемый результат:
{Abbott and Costello=Comedy}
4.3. Карта<Объект,Объект>
Десериализация
Наконец, давайте изменим наш входной JSON и TypeReference
нашего пункта назначения на 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);
toString()
нашего объекта Map<MyPair, MyPair>
:
{Abbott and Costello=Comedy and 1940s}
5. Вывод
В этой краткой статье мы узнали, как сериализовать и десериализовать карты
Java в строки в формате JSON и из них.
Как всегда, приведенный в этой статье пример доступен в репозитории GitHub .