В современном мире программирования, где JSON стал предпочтительным протоколом для передачи информации от клиента к серверу, не будет преувеличением сказать, что XML — это волна, которая была забита до смерти на берегу.
К сожалению, в JDK нет библиотеки JSON, поэтому я не знаю, почему она не работает. Во времена Log4j для конкурса также был запущен java.util.logging, хотя в итоге им пользовались немногие.
PS: Четырёхвагонная система лога: Log4j, SLF4J, Logback, Log4j2
адрес:Disk.Baidu.com/Yes/1DP Online Q Number T5…Пароль: fxxy
Причина, по которой Java настолько мощная, заключается в том, что ее экология очень совершенна. JDK не имеет библиотеки JSON, но доступны сторонние библиотеки. Это довольно хорошо. , парсер JSON по умолчанию в Spring Boot.
Как это доказать?
Когда мы создаем новый веб-проект Spring Boot через стартер, мы видим Джексона в зависимостях Maven.
Джексон имеет много преимуществ:
- Скорость парсинга больших файлов относительно высока;
- Меньше памяти занято во время выполнения, а производительность выше;
- API является гибким, его легко расширять и настраивать.
Основной модуль Джексона состоит из трех частей:
- jackson-core, основной пакет, предоставляет соответствующие API-интерфейсы, основанные на синтаксическом анализе в «потоковом режиме», включая JsonPaser и JsonGenerator.
- jackson-annotations, пакет аннотаций, предоставляет стандартные функции аннотации;
- jackson-databind , пакет привязки данных, предоставляет связанные API ( ObjectMapper ) на основе синтаксического анализа «привязки объекта» и связанные API (JsonNode) на основе синтаксического анализа «древовидной модели».
01. Представьте зависимости Джексона
Чтобы использовать Jackson, вам нужно добавить зависимость Jackson в файл pom.xml.
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.10.1</version>
</dependency>
jackson-databind зависит от jackson-core и jackson-annotations, поэтому после добавления jackson-databind Maven автоматически добавит в проект jackson-core и jackson-annotations.
Вот что делает Мейвен таким милым, поскольку он может тайком помогать нам делать то, что нам нужно.
02. Используйте ObjectMapper
Наиболее часто используемым API Джексона является ObjectMapper, основанный на «привязке объектов», который сериализует объекты Java в JSON с помощью серии методов writeValue и может храниться в разных форматах.
-
writeValueAsString(Object value)
метод для хранения объекта в виде строки -
writeValueAsBytes(Object value)
метод для хранения объекта в виде массива байтов -
writeValue(File resultFile, Object value)
метод для сохранения объекта в виде файла
Взгляните на пример кода, хранящегося в виде строки:
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class Demo {
public static void main(String[] args) throws JsonProcessingException {
Writer wanger = new Writer("沉默王二", 18);
ObjectMapper mapper = new ObjectMapper();
String jsonString = mapper.writerWithDefaultPrettyPrinter()
.writeValueAsString(wanger);
System.out.println(jsonString);
}
}
class Writer {
private String name;
private int age;
public Writer(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;
}
}
Вывод программы следующий:
{
"name" : "沉默王二",
"age" : 18
}
Не все поля поддерживают сериализацию и десериализацию, необходимо соблюдать следующие правила:
- Если модификатор поля является общедоступным, поле можно сериализовать и десериализовать (не стандартная запись).
- Поле является сериализуемым и десериализуемым, если его модификатор не является общедоступным, но его методы получения и установки являются общедоступными. Метод получения используется для сериализации, а метод установки используется для десериализации.
- Если поле имеет только общедоступный метод установки и не имеет общедоступного метода получения, поле можно использовать только для десериализации.
Если вы хотите изменить правила сериализации и десериализации по умолчанию, вам нужно вызвать метод ObjectMapper.setVisibility()
метод. В противном случае будет выдано исключение InvalidDefinitionException.
ObjectMapper десериализует JSON в объекты Java из разных источников данных с помощью серии методов readValue.
-
readValue(String content, Class<T> valueType)
метод десериализации строки в объект Java -
readValue(byte[] src, Class<T> valueType)
метод десериализации массива байтов в объект Java -
readValue(File src, Class<T> valueType)
метод десериализации файла в объект Java
Взгляните на пример кода, который десериализует строку в объект Java:
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class Demo {
public static void main(String[] args) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
String jsonString = "{\n" +
" \"name\" : \"沉默王二\",\n" +
" \"age\" : 18\n" +
"}";
Writer deserializedWriter = mapper.readValue(jsonString, Writer.class);
System.out.println(deserializedWriter);
}
}
class Writer{
private String name;
private int age;
// getter/setter
@Override
public String toString() {
return "Writer{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
Вывод программы следующий:
Writer{name='沉默王二', age=18}
PS: если у десериализованного объекта есть конструктор с параметрами, он должен иметь пустой конструктор по умолчанию, иначе он выдастInvalidDefinitionException
одна линия.
Exception in thread "main" com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `com.itwanger.jackson.Writer` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
at [Source: (String)"{
"name" : "沉默王二",
"age" : 18
}"; line: 2, column: 3]
at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67)
at com.fasterxml.jackson.databind.DeserializationContext.reportBadDefinition(DeserializationContext.java:1589)
at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1055)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1297)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:326)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:159)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4202)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3205)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3173)
at com.itwanger.jackson.Demo.main(Demo.java:19)
Наиболее часто используемым API Джексона является ObjectMapper, основанный на «привязке объектов».
ObjectMapper также может анализировать JSON в объекты JsonNode на основе «древовидной модели», см. пример ниже.
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JsonNodeDemo {
public static void main(String[] args) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
String json = "{ \"name\" : \"沉默王二\", \"age\" : 18 }";
JsonNode jsonNode = mapper.readTree(json);
String name = jsonNode.get("name").asText();
System.out.println(name); // 沉默王二
}
}
С помощью TypeReference вы можете преобразовать строковый массив JSON в общий список, см. следующий пример:
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.List;
public class TypeReferenceDemo {
public static void main(String[] args) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
String json = "[{ \"name\" : \"沉默王三\", \"age\" : 18 }, { \"name\" : \"沉默王二\", \"age\" : 19 }]";
List<Author> listAuthor = mapper.readValue(json, new TypeReference<List<Author>>(){});
System.out.println(listAuthor);
}
}
class Author{
private String name;
private int age;
// getter/setter
// toString
}
03. Более продвинутая конфигурация
Очень важным фактором удивительности Jackson является то, что он может создавать очень гибкие индивидуальные настройки.
В практических сценариях приложений JSON часто имеет некоторые поля, которых нет в объектах Java.В настоящее время, если он анализируется напрямую, будет выдано исключение UnrecognizedPropertyException.
Вот набор строк JSON:
String jsonString = "{\n" +
" \"name\" : \"沉默王二\",\n" +
" \"age\" : 18\n" +
" \"sex\" : \"男\",\n" +
"}";
Но в объекте Writer Java не определено поле пола:
class Writer{
private String name;
private int age;
// getter/setter
}
Попробуем разобрать:
ObjectMapper mapper = new ObjectMapper();
Writer deserializedWriter = mapper.readValue(jsonString, Writer.class);
Неудивительно, что было выброшено исключение, и пол не был распознан.
Exception in thread "main" com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "sex" (class com.itwanger.jackson.Writer), not marked as ignorable (2 known properties: "name", "age"])
at [Source: (String)"{
"name" : "沉默王二",
"age" : 18,
"sex" : "男"
}"; line: 4, column: 12] (through reference chain: com.itwanger.jackson.Writer["sex"])
Как это сделать? в состоянии пройтиconfigure()
Метод игнорирует эти «нераспознанные» поля.
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
Кроме того, есть другая полезная информация о конфигурации для понимания:
// 在序列化时忽略值为 null 的属性
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
// 忽略值为默认值的属性
mapper.setDefaultPropertyInclusion(JsonInclude.Include.NON_DEFAULT);
04. Обработка форматов даты
Для полей типа даты, таких как java.util.Date, если формат не указан, он будет отображаться как данные длинного типа после сериализации, а удобочитаемость этого формата по умолчанию очень плохая.
{
"age" : 18,
"birthday" : 1606358621209
}
Как это сделать?
Первый вариант — использовать на геттере@JsonFormat
аннотация.
private Date birthday;
// GMT+8 是指格林尼治的标准时间,在加上八个小时表示你现在所在时区的时间
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
Давайте еще раз посмотрим на результаты:
{
"age" : 18,
"birthday" : "2020-11-26 03:02:30"
}
Конкретный код выглядит следующим образом:
ObjectMapper mapper = new ObjectMapper();
Writer wanger = new Writer("沉默王二", 18);
wanger.setBirthday(new Date());
String jsonString = mapper.writerWithDefaultPrettyPrinter()
.writeValueAsString(wanger);
System.out.println(jsonString);
Вторая схема, вызывающая ObjectMappersetDateFormat()
метод.
ObjectMapper mapper = new ObjectMapper();
mapper.setDateFormat(StdDateFormat.getDateTimeInstance());
Writer wanger = new Writer("沉默王二", 18);
wanger.setBirthday(new Date());
String jsonString = mapper.writerWithDefaultPrettyPrinter()
.writeValueAsString(wanger);
System.out.println(jsonString);
Результат выглядит следующим образом:
{
"name" : "沉默王二",
"age" : 18,
"birthday" : "2020年11月26日 上午11:09:51"
}
05. Фильтрация полей
При сериализации объектов Java в JSON может потребоваться фильтровать некоторые поля и не отображать их в JSON.У Джексона относительно простая реализация.
@JsonIgnore используется для фильтрации одного поля.
@JsonIgnore
public String getName() {
return name;
}
@JsonIgnoreProperties используется для фильтрации нескольких полей.
@JsonIgnoreProperties(value = { "age","birthday" })
class Writer{
private String name;
private int age;
private Date birthday;
}
06. Пользовательская сериализация и десериализация
Когда стандартная сериализация и десериализация Джексона не может удовлетворить фактические потребности разработки, можно настроить новые классы сериализации и десериализации.
Пользовательские классы сериализации должны наследовать StdSerializer и переопределятьserialize()
метод, используя JsonGenerator для генерации JSON, пример выглядит следующим образом:
public class CustomSerializer extends StdSerializer<Man> {
protected CustomSerializer(Class<Man> t) {
super(t);
}
public CustomSerializer() {
this(null);
}
@Override
public void serialize(Man value, JsonGenerator gen, SerializerProvider provider) throws IOException {
gen.writeStartObject();
gen.writeStringField("name", value.getName());
gen.writeEndObject();
}
}
class Man{
private int age;
private String name;
public Man(int age, String name) {
this.age = age;
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
После определения пользовательских классов сериализации, чтобы вызывать их в программе, вам необходимо зарегистрировать их в модуле ObjectMapper, пример выглядит следующим образом:
ObjectMapper mapper = new ObjectMapper();
SimpleModule module =
new SimpleModule("CustomSerializer", new Version(1, 0, 0, null, null, null));
module.addSerializer(Man.class, new CustomSerializer());
mapper.registerModule(module);
Man man = new Man( 18,"沉默王二");
String json = mapper.writeValueAsString(man);
System.out.println(json);
Вывод программы следующий:
{"name":"沉默王二"}
Поле age не добавляется в пользовательский класс сериализатора CustomSerializer, поэтому выводится только поле имени.
Давайте взглянем на пользовательский класс десериализации, унаследуем StdDeserializer и заодно перепишем его.deserialize()
метод, используйте JsonGenerator для чтения JSON, пример выглядит следующим образом:
public class CustomDeserializer extends StdDeserializer<Woman> {
protected CustomDeserializer(Class<?> vc) {
super(vc);
}
public CustomDeserializer() {
this(null);
}
@Override
public Woman deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
JsonNode node = p.getCodec().readTree(p);
Woman woman = new Woman();
int age = (Integer) ((IntNode) node.get("age")).numberValue();
String name = node.get("name").asText();
woman.setAge(age);
woman.setName(name);
return woman;
}
}
class Woman{
private int age;
private String name;
public Woman() {
}
// getter/setter
@Override
public String toString() {
return "Woman{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}
Считайте JSON в древовидную структуру с помощью JsonNode, затем прочитайте соответствующие поля с помощью метода get JsonNode, а затем сгенерируйте новый объект Java и верните его.
После определения пользовательских классов десериализации, если вы хотите вызывать их в программе, вам также необходимо зарегистрировать их в модуле ObjectMapper, пример выглядит следующим образом:
ObjectMapper mapper = new ObjectMapper();
SimpleModule module =
new SimpleModule("CustomDeserializer", new Version(1, 0, 0, null, null, null));
module.addDeserializer(Woman.class, new CustomDeserializer());
mapper.registerModule(module);
String json = "{ \"name\" : \"三妹\", \"age\" : 18 }";
Woman woman = mapper.readValue(json, Woman.class);
System.out.println(woman);
Вывод программы следующий:
Woman{age=18, name='三妹'}
07. Заключение
Упс, вроде неплохо, Джексон определенно заслуживает три слова «самый классный», хотя это немного фальшиво. Если вам нужна простая сериализация и десериализация, используйте методы записи и чтения ObjectMapper.
Если вы хотите пойти дальше, вам нужно выполнить некоторую пользовательскую настройку ObjectMapper или добавить некоторые аннотации и напрямую настроить классы сериализации и десериализации, которые ближе к некоторым объектам Java.
Следует отметить, что с полями в формате даты следует быть осторожнее, стараться не использовать конфигурацию по умолчанию, а читабельность очень плохая.
Что ж, благодаря систематическому введению в эту статью, я считаю, что вы полностью поняли Джексона, увидимся в следующей статье.
P.S. Если вдруг вам нужен расширенный маршрут по Java, то у меня есть такой, на его организацию у меня ушло почти 3 дня, он достаточно популярен, набрал более 2000 лайков, и каждый этап очень подробно расписан.
Если вам это просто нужно, вы можете щелкнуть ссылку выше, чтобы взглянуть, я надеюсь, что это может вам немного помочь (давай).