Если вы считаете, что содержание этого блога будет для вас полезным или вдохновляющим, подписывайтесь на мой блог, чтобы как можно скорее получать последние технические статьи и руководства. В то же время вы также можете оставить сообщение в области комментариев, чтобы поделиться своими мыслями и предложениями. Спасибо за Вашу поддержку!
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. Содержание, представленное в этой статье, охватывает большую часть использования библиотеки Джексона. Я полагаю, что читатели имеют предварительное представление о библиотеке Джексона. В реальной разработке вы можете выбирать различные методы сериализации и десериализации в соответствии с вашими потребностями, чтобы лучше соответствовать потребностям бизнеса.
Если вы считаете, что содержание этого блога будет для вас полезным или вдохновляющим, подписывайтесь на мой блог, чтобы как можно скорее получать последние технические статьи и руководства. В то же время вы также можете оставить сообщение в области комментариев, чтобы поделиться своими мыслями и предложениями. Спасибо за Вашу поддержку!