Сериализация и десериализация JSON с использованием библиотеки Джексона

Если вы считаете, что содержание этого блога будет для вас полезным или вдохновляющим, подписывайтесь на мой блог, чтобы как можно скорее получать последние технические статьи и руководства. В то же время вы также можете оставить сообщение в области комментариев, чтобы поделиться своими мыслями и предложениями. Спасибо за Вашу поддержку!

1. Преамбула

В современной веб-разработке JSON (нотация объектов JavaScript) стала широко используемым форматом данных для передачи и хранения внешних и внутренних данных. Java — это объектно-ориентированный язык программирования, а JSON — это данные в формате пары «ключ-значение», поэтому в Java вам необходимо преобразовать объект Java в строку JSON или преобразовать строку JSON в объект Java. Этот процесс представляет собой сериализацию и десериализацию JSON.

Для сериализации и десериализации JSON в Java существует множество библиотек с открытым исходным кодом, из которых библиотека Джексона является одной из самых популярных. Библиотека Джексона предоставляет множество функций для гибкой сериализации и десериализации JSON с превосходной производительностью.

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

2. Что такое сериализация и десериализация JSON

Сериализация JSON — это процесс преобразования объекта Java в строку JSON. В процессе сериализации JSON свойства объекта Java будут преобразованы в пары "ключ-значение" объекта JSON. Если объект Java содержит другие объекты или коллекции Java, эти вложенные объекты также будут преобразованы во вложенные объекты JSON и массивы JSON. .

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

В-третьих, введение в библиотеку Джексона

Библиотека Джексона — это библиотека обработки JSON на основе Java, которая предоставляет гибкий анализатор JSON и генератор JSON, которые могут легко преобразовывать объекты Java и данные JSON. Библиотека Джексона очень проста в использовании и обладает отличной производительностью, поэтому широко используется при разработке Java.

Библиотека Джексона имеет два основных класса: ​ObjectMapper​и ​JsonNode​.

Этот класс​ObjectMapper​ является наиболее важным классом в библиотеке Джексона, который обеспечивает преобразование между сериализацией и десериализацией объектов Java и JSON. ​ObjectMapper​Экземпляры класса

​​​​Класс​JsonNode​ представляет собой абстрактный класс, представляющий узел JSON. Класс​JsonNode​ имеет несколько подклассов, таких как ​ObjectNode​, ​ArrayNode​, ​ValueNode​и т. д. , соответствующих объектам, массивам и значениям в JSON. Класс​JsonNode​ предоставляет удобные методы для чтения значения узла JSON.

4. Сериализация JSON базового типа.

1. Сериализация объектов

Самый простой способ преобразовать объект Java в строку JSON — ​ObjectMapper​использовать ​writeValueAsString​метод класса. Этот метод получает объект Java в качестве параметра и возвращает строку JSON.

Например:

ObjectMapper mapper = new ObjectMapper();
User user = new User("Tom", 20);
String json = mapper.writeValueAsString(user);

В приведенном выше коде мы создаем ​User​объект и используем ​ObjectMapper​класс для его сериализации в строку JSON. ​User​Определение класса

public class User {
    private String name;
    private int age;
    
    public User() {
    }
    
    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public int getAge() {
        return age;
    }
    
    public void setAge(int age) {
        this.age = age;
    }
}

Результирующая строка JSON выглядит следующим образом:

{"name":"Tom","age":20}

2. Сериализация коллекции

Помимо сериализации отдельного Java-объекта, библиотека Джексона также поддерживает сериализацию Java-коллекций, в том числе ​List​, ​Set​​​и ​Map​т. д. Коллекцию Java можно сериализовать в строку JSON с помощью метода ​ObjectMapper​класса .​writeValueAsString​

ObjectMapper mapper = new ObjectMapper();
List<User> users = new ArrayList<>();
users.add(new User("Tom", 20));
users.add(new User("Jerry", 22));
String json = mapper.writeValueAsString(users);

В приведенном выше коде мы создаем ​List​коллекцию и ​User​добавляем в нее два объекта, а затем используем ​ObjectMapper​класс для сериализации коллекции в строку JSON.

Результирующая строка JSON выглядит следующим образом:

[{"name":"Tom","age":20},{"name":"Jerry","age":22}]

3. Сериализованный тип перечисления

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

public enum Gender {
    MALE, FEMALE
}

Чтобы сериализовать тип перечисления в строку JSON, нам просто нужно добавить ​@JsonFormat​аннотацию и указать формат сериализации. Например, следующий код сериализует тип перечисления, используя заглавные буквы:

public class User {
    private String name;
    private int age;
    private Gender gender;
    
    // getters and setters
}

ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT);

User user = new User();
user.setName("Tom");
user.setAge(20);
user.setGender(Gender.MALE);

String json = mapper.writeValueAsString(user);
System.out.println(json);

Вывод следующий:

{
  "name" : "Tom",
  "age" : 20,
  "gender" : "MALE"
}

В приведенном выше коде мы сначала определяем ​User​класс , который содержит поле типа перечисления ​gender​. Затем мы используем ​ObjectMapper​этот класс для ​User​сериализации объекта в строку JSON и печати результата. Как видите, значение типа перечисления было сериализовано в строковый тип.

4. Сериализация типа времени Java

В практических приложениях нам часто необходимо сериализовать типы времени Java в строки JSON для передачи в другие системы или хранения в базах данных. Библиотека Джексона обеспечивает очень удобную поддержку сериализации типов времени Java 8 (например ​java.time.LocalDateTime​, ) в строки JSON.

Вот пример сериализации типа времени Java с использованием библиотеки Джексона:

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.databind.SerializationFeature;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;

public class JacksonDemo {
    public static void main(String[] args) throws Exception {
        ObjectMapper mapper = new ObjectMapper();
        mapper.registerModule(new JavaTimeModule());
        mapper.enable(SerializationFeature.INDENT_OUTPUT);
        
        LocalDateTime now = LocalDateTime.now(ZoneId.of("Asia/Shanghai"));
        String json = mapper.writeValueAsString(now);
        System.out.println(json);
        
        LocalDateTime parsed = mapper.readValue(json, LocalDateTime.class);
        System.out.println(parsed.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
    }
}

В приведенном выше коде мы сначала создаем ​ObjectMapper​объект и регистрируем ​JavaTimeModule​модуль для поддержки сериализации типов времени Java 8. Затем мы используем ​LocalDateTime.now()​этот метод , чтобы получить текущее время и сериализовать его в строку JSON. Обратите внимание, что мы используем для ​ZoneId.of("Asia/Shanghai")​указания часового пояса пекинское время.

Далее мы десериализуем строку JSON в объект ​ObjectMapper​используя метод. Наконец, мы форматируем десериализованный объект в формат времени ISO-8601 и распечатываем его.​readValue()​​LocalDateTime​

Вывод следующий:

"2022-02-23T14:25:23.845"
2022-02-23T14:25:23.845

Как видите, мы успешно сериализовали текущее время в строку JSON и восстановили исходный объект времени при десериализации.

Следует отметить, что при сериализации типов времени Java библиотека Джексона по умолчанию использует формат времени ISO-8601. Если вам нужно использовать другие форматы времени, вы можете использовать аннотацию , чтобы указать формат времени. Например:@JsonFormat

@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
private LocalDateTime startTime;

В приведенном выше коде мы указали формат времени и часовой пояс с помощью ​@JsonFormat​аннотации . Таким образом, библиотека Джексона будет использовать указанный формат времени для сериализации времени.

Пять основных типов десериализации JSON.

Основной способ преобразования строки JSON в объект Java — ​ObjectMapper​использовать ​readValue​метод класса. Этот метод получает два параметра: строку JSON и класс Java. Он десериализует строку JSON в указанный объект класса Java.

1. Десериализовать один объект

Сначала давайте посмотрим, как десериализовать строку JSON в один объект Java. Предположим, у нас есть строка JSON, представляющая ​User​объект :

{
    "name": "Tom",
    "age": 20
}

Его можно десериализовать в объект , используя метод ​ObjectMapper​класса :​readValue​​User​

ObjectMapper mapper = new ObjectMapper();
String json = "{\"name\":\"Tom\",\"age\":20}";
User user = mapper.readValue(json, User.class);

В приведенном выше коде мы ​ObjectMapper​создаем экземпляр класса и десериализуем строку JSON в ​User​объект.

2. Десериализация объектов коллекции

Помимо десериализации отдельного объекта Java, библиотека Джексона также поддерживает десериализацию коллекций Java, в том числе ​List​, ​Set​и ​Map​т.д. Строку JSON можно десериализовать в коллекцию Java с помощью метода ​ObjectMapper​класса .​readValue​

ObjectMapper mapper = new ObjectMapper();
String json = "[{\"name\":\"Tom\",\"age\":20},{\"name\":\"Jerry\",\"age\":22}]";
List<User> users = mapper.readValue(json, new TypeReference<List<User>>() {});

В приведенном выше коде мы создали строку JSON, содержащую два ​User​объекта , и десериализовали ее в ​List​коллекцию.

Следует отметить, что из-за универсального механизма стирания Java вы не можете напрямую ​List<User>​перейти к ​readValue​методу, и вам нужно использовать ​TypeReference​класс для указания типа коллекции. Это​TypeReference​ вспомогательный класс, предоставляемый библиотекой Джексона, который используется для получения информации о типе универсальных параметров.

3. Десериализовать тип перечисления.

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

Пример кода выглядит следующим образом:

Сначала определите тип перечисления:

public enum Gender {
    MALE,
    FEMALE
}

Затем предположим, что у нас есть следующие данные JSON:

{
    "name": "Tom",
    "gender": "MALE"
}

Мы можем преобразовать строки данных JSON в константы перечисления в Java, используя следующий код:

ObjectMapper mapper = new ObjectMapper();
String json = "{\"name\": \"Tom\", \"gender\": \"MALE\"}";
Map<String, Object> map = mapper.readValue(json, new TypeReference<Map<String, Object>>(){});
Gender gender = Gender.valueOf(map.get("gender").toString());

Приведенный выше код сначала создает объект с помощью класса ObjectMapper, а затем анализирует данные JSON в объект Map. Наконец, мы можем преобразовать строки в карте в константы перечисления, используя метод valueOf().

4. Десериализовать тип времени Java

В Java тип времени — это очень распространенный тип данных, включая Date, LocalDate, LocalTime, LocalDateTime и т. д. В данных JSON типы времени обычно представлены строками. С помощью библиотеки Джексона можно легко преобразовать строки данных JSON в типы времени в Java.

Пример кода выглядит следующим образом:

Предположим, у нас есть следующие данные JSON:

{
    "name": "Tom",
    "birthday": "2000-01-01"
}

Мы можем использовать следующий код для преобразования строки данных JSON в тип LocalDate в Java:

ObjectMapper mapper = new ObjectMapper();
String json = "{\"name\": \"Tom\", \"birthday\": \"2000-01-01\"}";
Map<String, Object> map = mapper.readValue(json, new TypeReference<Map<String, Object>>(){});
LocalDate birthday = LocalDate.parse(map.get("birthday").toString());

Приведенный выше код сначала создает объект с помощью класса ObjectMapper, а затем анализирует данные JSON в объект Map. Наконец, мы можем использовать метод parse() для преобразования строк на карте в тип LocalDate. Десериализация других типов времени аналогична.

Шесть: пользовательская сериализация и десериализация.

В некоторых случаях поведение сериализации и десериализации по умолчанию, предоставляемое библиотекой Джексона, может не соответствовать требованиям, и требуются пользовательские правила сериализации и десериализации. Например, при сериализации ​User​объекта мы хотим сериализовать возраст как строковый тип вместо целочисленного типа по умолчанию.

1. Пользовательская сериализация

Чтобы настроить правила сериализации, нужно создать класс, реализующий ​JsonSerializer​интерфейс . ​​— это​JsonSerializer​ абстрактный класс, предоставляемый библиотекой Джексона, который используется для сериализации объектов Java в строки JSON.

Вот пример сериализации возраста ​User​объекта в виде строки:

public class AgeToStringSerializer extends JsonSerializer<Integer> {
    @Override
    public void serialize(Integer value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        gen.writeString(value.toString());
    }
}

В приведенном выше коде мы определили класс ​AgeToStringSerializer​с именем , который наследуется от ​JsonSerializer​и переопределяет ​serialize​метод . Метод получает три параметра: объект Java, который необходимо сериализовать, ​JsonGenerator​объект, , и ​SerializerProvider​объект, предоставляющий некоторую информацию, необходимую для сериализации.

В ​serialize​методе мы ​value​преобразуем параметр в строковый тип и используем ​gen.writeString​метод для записи его ​JsonGenerator​в объект.

Далее нам ​User​нужно ​age​использовать ​@JsonSerialize​аннотацию класса, чтобы указать собственный ​AgeToStringSerializer​класс для сериализации:

public class User {
    private String name;
    @JsonSerialize(using = AgeToStringSerializer.class)
    private int age;
    private Address address;
    
    // ...
}

Затем мы можем использовать ​ObjectMapper​этот класс для ​User​сериализации объекта в строку JSON, как и раньше:

ObjectMapper mapper = new ObjectMapper();
User user = new User("Tom", 20, new Address("New York", "NY"));
String json = mapper.writeValueAsString(user);

Результирующая строка JSON выглядит следующим образом:

{"name":"Tom","age":"20","address":{"city":"New York","state":"NY"}}

2. Пользовательская десериализация

Подобно пользовательской сериализации, для настройки правил десериализации необходимо создать класс, реализующий ​JsonDeserializer​интерфейс . ​​— это​JsonDeserializer​ абстрактный класс, предоставляемый библиотекой Джексона, который используется для десериализации строк JSON в объекты Java.

Вот пример, который десериализует возраст ​User​объекта из строкового типа в целочисленный тип:

public class StringToAgeDeserializer extends JsonDeserializer<Integer> {
    @Override
    public Integer deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        String value = p.getValueAsString();
        return Integer.parseInt(value);
    }
}

В приведенном выше коде мы определили ​StringToAgeDeserializer​класс , который наследуется от ​JsonDeserializer​класса и переопределяет ​deserialize​метод . Метод получает два параметра: ​JsonParser​объект и ​DeserializationContext​объект, предоставляющий некоторую информацию, необходимую при десериализации.

В ​deserialize​методе мы сначала используем ​p.getValueAsString​метод для получения значения в строке JSON и преобразования его в строковый тип. Затем мы используем ​Integer.parseInt​этот метод для преобразования значения типа string в целое число и возвращаем результат.

Далее нам ​User​нужно ​age​использовать ​@JsonDeserialize​аннотацию класса, чтобы указать собственный ​StringToAgeDeserializer​класс для десериализации:

public class User {
    private String name;
    @JsonSerialize(using = AgeToStringSerializer.class)
    @JsonDeserialize(using = StringToAgeDeserializer.class)
    private int age;
    private Address address;
    
    // ...
}

Затем мы можем десериализовать строку JSON в объект, используя ​ObjectMapper​класс, ​User​:

ObjectMapper mapper = new ObjectMapper();
String json = "{\"name\":\"Tom\",\"age\":\"20\",\"address\":{\"city\":\"New York\",\"state\":\"NY\"}}";
User user = mapper.readValue(json, User.class);

В приведенном выше коде мы сначала определяем строку JSON и ​ObjectMapper​используем ​readValue​метод класса для ее десериализации в ​User​объект . Поскольку значение ​age​поля является строковым типом, ​StringToAgeDeserializer​во время десериализации оно будет анализироваться с использованием нашего специального класса. В итоге мы получим ​User​объект , ​age​значение поля которого равно 20 целочисленного типа.

5. Назначение и использование общих аннотаций

1. @JsonProperty

Аннотация @JsonProperty используется для указания имени свойства в объекте Java при его сериализации в данные JSON. Если эта аннотация не используется, по умолчанию используется имя свойства. При десериализации эта аннотация также используется для указания того, какому свойству объекта Java соответствует имя свойства в данных JSON.

Пример кода выглядит следующим образом:

Предположим, у нас есть следующий объект Java:

public class Person {
    private String name;
    private int age;

    @JsonProperty("person_gender")
    private Gender gender;

    // getters and setters
}

Мы можем использовать аннотацию @JsonProperty, чтобы указать имя свойства, например свойство пола в приведенном выше коде. При сериализации этого объекта Java в данные JSON атрибут пола будет сериализован как поле «person_gender».

ObjectMapper mapper = new ObjectMapper();
Person person = new Person();
person.setName("Tom");
person.setAge(20);
person.setGender(Gender.MALE);
String json = mapper.writeValueAsString(person);
System.out.println(json);

Результат:

{"name":"Tom","age":20,"person_gender":"MALE"}

2. @JsonFormat

Аннотация @JsonFormat используется для указания формата типа даты и времени в объекте Java при его сериализации в данные JSON. Вы можете использовать эту аннотацию для указания формата даты и времени, часового пояса и т. д.

Пример кода выглядит следующим образом:

Предположим, у нас есть следующий объект Java:

public class Person {
    private String name;

    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
    private LocalDate birthday;

    // getters and setters
}

Мы можем использовать аннотацию @JsonFormat, чтобы указать формат даты и времени, например атрибут дня рождения в приведенном выше коде. При сериализации этого объекта Java в данные JSON свойство дня рождения будет сериализовано в строку даты в формате «гггг-ММ-дд».

ObjectMapper mapper = new ObjectMapper();
Person person = new Person();
person.setName("Tom");
person.setBirthday(LocalDate.of(2000, 1, 1));
String json = mapper.writeValueAsString(person);
System.out.println(json);

Результат:

{"name":"Tom","birthday":"2000-01-01"}

3. @JsonIgnore

Аннотация @JsonIgnore используется для игнорирования операции свойства в объекте Java во время сериализации и десериализации. Атрибуты, отмеченные этой аннотацией, не будут включены при сериализации в данные JSON, а также им не будут присвоены значения при десериализации.

Пример кода выглядит следующим образом:

Предположим, у нас есть следующий объект Java:

public class Person {
    private String name;
    private int age;

    @JsonIgnore
    private Gender gender;

    // getters and setters
}

Мы можем использовать аннотацию @JsonIgnore, чтобы игнорировать атрибут пола, который не будет включен при сериализации в данные JSON.

ObjectMapper mapper = new ObjectMapper();
Person person = new Person();
person.setName("Tom");
person.setAge(20);
person.setGender(Gender.MALE);
String json = mapper.writeValueAsString(person);
System.out.println(json);

Результат:

{"name":"Tom","age":20}

4. @JsonInclude

Аннотация @JsonInclude используется для указания условий сериализации определенных свойств объекта Java в данные JSON, например, если свойство имеет значение NULL или значение по умолчанию, свойство не включается.

Пример кода выглядит следующим образом:

Предположим, у нас есть следующий объект Java:

@JsonInclude(JsonInclude.Include.NON_NULL)
public class Person {
    private String name;
    private Integer age;
    private Gender gender;

    // getters and setters
}

Мы можем использовать аннотацию @JsonInclude, чтобы указать, что при сериализации в данные JSON, если атрибут age имеет значение null, атрибут не будет включен.

ObjectMapper mapper = new ObjectMapper();
Person person = new Person();
person.setName("Tom");
person.setAge(null);
person.setGender(Gender.MALE);
String json = mapper.writeValueAsString(person);
System.out.println(json);

Результат:

{"name":"Tom","gender":"MALE"}

5. @JsonTypeInfo

Аннотация @JsonTypeInfo используется для указания информации о типе объектов Java во время сериализации и десериализации. Эту аннотацию можно использовать для указания фактического типа подкласса, а данные JSON можно правильно преобразовать в соответствующий объект Java во время десериализации.

Пример кода выглядит следующим образом:

Предположим, у нас есть следующий объект Java:

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
@JsonSubTypes({
    @JsonSubTypes.Type(value = Dog.class, name = "dog"),
    @JsonSubTypes.Type(value = Cat.class, name = "cat")
})
public abstract class Animal {
    private String name;

    // getters and setters
}

public class Dog extends Animal {
    private String breed;

    // getters and setters
}

public class Cat extends Animal {
    private String color;

    // getters and setters
}

Мы можем использовать аннотацию @JsonTypeInfo, чтобы указать информацию о типе подкласса объекта Animal, и данные JSON можно правильно преобразовать в соответствующий объект Java во время сериализации и десериализации.

ObjectMapper mapper = new ObjectMapper();
Animal dog = new Dog();
dog.setName("Bobby");
((Dog) dog).setBreed("Bulldog");
String json = mapper.writeValueAsString(dog);
System.out.println(json);
Animal animal = mapper.readValue("{\"name\":\"Kitty\",\"type\":\"cat\",\"color\":\"white\"}", Animal.class);
System.out.println(animal.getClass().getName());
System.out.println(((Cat) animal).getColor());

Результат:

{"type":"dog","name":"Bobby","breed":"Bulldog"}
com.example.jackson.Cat
white

Подведем итог

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

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

Если вы считаете, что содержание этого блога будет для вас полезным или вдохновляющим, подписывайтесь на мой блог, чтобы как можно скорее получать последние технические статьи и руководства. В то же время вы также можете оставить сообщение в области комментариев, чтобы поделиться своими мыслями и предложениями. Спасибо за Вашу поддержку!

рекомендация

отblog.csdn.net/bairo007/article/details/132520849