利用Jackson解析JSON的詳細(xì)實(shí)現(xiàn)教程
JSON 對于開發(fā)者并不陌生,如今的 WEB 服務(wù)、移動應(yīng)用、甚至物聯(lián)網(wǎng)大多都是以 JSON 作為數(shù)據(jù)交換的格式。學(xué)習(xí) JSON 格式的操作工具對開發(fā)者來說是必不可少的。這篇文章將介紹如何使用 Jackson 開源工具庫對 JSON 進(jìn)行常見操作。

JSON logo
JSON 介紹
什么是 JSON ?JSON 是 ”JavaScript Object Notation“ 的縮寫,JSON 是一種基于文本的格式,可以把它理解為是一個(gè)結(jié)構(gòu)化的數(shù)據(jù),這個(gè)結(jié)構(gòu)化數(shù)據(jù)中可以包含鍵值映射、嵌套對象以及數(shù)組等信息。
{
??"array":?[
????1,
????2,
????3
??],
??"boolean":?true,
??"color":?"gold",
??"null":?null,
??"number":?123,
??"object":?{
????"a":?"b",
????"c":?"d"
??},
??"string":?"www.wdbyte.com"
}Jackson 介紹
Jackson 和 FastJson 一樣,是一個(gè) Java 語言編寫的,可以進(jìn)行 JSON 處理的開源工具庫,Jackson 的使用非常廣泛,Spring 框架默認(rèn)使用 Jackson 進(jìn)行 JSON 處理。
Jackson 有三個(gè)核包,分別是 Streaming、Databid、Annotations,通過這些包可以方便的對 JSON 進(jìn)行操作。
• Streaming[1] 在 jackson-core 模塊。定義了一些流處理相關(guān)的 API 以及特定的 JSON 實(shí)現(xiàn)。
• Annotations[2] 在 jackson-annotations 模塊,包含了 Jackson 中的注解。
• Databind[3] 在 jackson-databind 模塊, 在 Streaming 包的基礎(chǔ)上實(shí)現(xiàn)了數(shù)據(jù)綁定,依賴于 Streaming 和 Annotations 包。
得益于 Jackson 高擴(kuò)展性的設(shè)計(jì),有很多常見的文本格式以及工具都有對 Jackson 的相應(yīng)適配,如 CSV、XML、YAML 等。
Jackson Maven 依賴
在使用 Jackson 時(shí),大多數(shù)情況下我們只需要添加 jackson-databind 依賴項(xiàng),就可以使用 Jackson 功能了,它依賴了下面兩個(gè)包。

jackson-databind 依賴
• com.fasterxml.jackson.core:jackson-annotations
• com.fasterxml.jackson.core:jackson-core
<dependency> ????<groupId>com.fasterxml.jackson.core</groupId> ????<artifactId>jackson-databind</artifactId> ????<version>2.13.3</version> </dependency>
為了方便這篇文章后續(xù)的代碼演示,我們同時(shí)引入 Junit 進(jìn)行單元測試和 Lombok 以減少 Get/Set 的代碼編寫。
<dependency> ????<groupId>org.junit.jupiter</groupId> ????<artifactId>junit-jupiter</artifactId> ????<version>5.8.2</version> ????<scope>test</scope> </dependency> <dependency> ????<groupId>org.projectlombok</groupId> ????<artifactId>lombok</artifactId> ????<version>1.18.22</version> </dependency>
ObjectMapper 對象映射器
ObjectMapper 是 Jackson 庫中最常用的一個(gè)類,使用它可以進(jìn)行 Java 對象和 JSON 字符串之間快速轉(zhuǎn)換。如果你用過 FastJson,那么 Jackson 中的 ObjectMapper 就如同 FastJson 中的 JSON 類。
這個(gè)類中有一些常用的方法:
• readValue() 方法可以進(jìn)行 JSON 的反序列化操作,比如可以將字符串、文件流、字節(jié)流、字節(jié)數(shù)組等將常見的內(nèi)容轉(zhuǎn)換成 Java 對象。
• writeValue() 方法可以進(jìn)行 JSON 的序列化操作,可以將 Java 對象轉(zhuǎn)換成 JSON 字符串。
大多數(shù)情況下,ObjectMapper 的工作原理是通過 Java Bean 對象的 Get/Set 方法進(jìn)行轉(zhuǎn)換時(shí)映射的,所以正確編寫 Java 對象的 Get/Set 方法尤為重要,不過 ObjectMapper 也提供了諸多配置,比如可以通過配置或者注解的形式對 Java 對象和 JSON 字符串之間的轉(zhuǎn)換過程進(jìn)行自定義。這些在下面部分都會介紹到。
Jackson JSON 基本操作
Jackson 作為一個(gè) Java 中的 JSON 工具庫,處理 JSON 字符串和 Java 對象是它最基本最常用的功能,下面通過一些例子來演示其中的用法。
Jackson JSON 序列化
編寫一個(gè) Person 類,定義三個(gè)屬性,名稱、年齡以及技能。
/**
?*?@author?https://www.wdbyte.com
?*/
@Data
public?class?Person?{
????private?String?name;
????private?Integer?age;
????private?List<String>?skillList;
}將 Java 對象轉(zhuǎn)換成 JSON 字符串。
import?java.util.Arrays;
import?com.fasterxml.jackson.core.JsonProcessingException;
import?com.fasterxml.jackson.databind.ObjectMapper;
import?org.junit.jupiter.api.Assertions;
import?org.junit.jupiter.api.Test;
/**
?*?@author?https://www.wdbyte.com
?*/
class?PersonTest?{
????ObjectMapper?objectMapper?=?new?ObjectMapper();
????@Test
????void?pojoToJsonString()?throws?JsonProcessingException?{
????????Person?person?=?new?Person();
????????person.setName("aLng");
????????person.setAge(27);
????????person.setSkillList(Arrays.asList("java",?"c++"));
????????String?json?=?objectMapper.writeValueAsString(person);
????????System.out.println(json);
????????String?expectedJson?=?"{\"name\":\"aLng\",\"age\":27,\"skillList\":[\"java\",\"c++\"]}";
????????Assertions.assertEquals(json,?expectedJson);
????}
}輸出的 JSON 字符串:
{"name":"aLng","age":27,"skillList":["java","c++"]}
Jackson 甚至可以直接把序列化后的 JSON 字符串寫入文件或者讀取成字節(jié)數(shù)組。
mapper.writeValue(new?File("result.json"),?myResultObject);
//?或者
byte[]?jsonBytes?=?mapper.writeValueAsBytes(myResultObject);
//?或者
String?jsonString?=?mapper.writeValueAsString(myResultObject);Jackson JSON 反序列化
直接貼出代碼:
package?com.wdbyte.jackson;
import?com.fasterxml.jackson.core.JsonProcessingException;
import?com.fasterxml.jackson.databind.ObjectMapper;
import?org.junit.jupiter.api.Assertions;
import?org.junit.jupiter.api.Test;
/**
?*?@author?https://www.wdbyte.com
?*/
class?PersonTest?{
????ObjectMapper?objectMapper?=?new?ObjectMapper();
????@Test
????void?jsonStringToPojo()?throws?JsonProcessingException?{
????????String?expectedJson?=?"{\"name\":\"aLang\",\"age\":27,\"skillList\":[\"java\",\"c++\"]}";
????????Person?person?=?objectMapper.readValue(expectedJson,?Person.class);
????????System.out.println(person);
????????Assertions.assertEquals(person.getName(),?"aLang");
????????Assertions.assertEquals(person.getSkillList().toString(),?"[java,?c++]");
????}
}輸出結(jié)果:
Person(name=aLang, age=27, skillList=[java, c++])
上面的例子演示了如何使用 Jackson 把一個(gè) JSON 字符串反序列化成 Java 對象,其實(shí) Jackson 對文件中的 JSON 字符串、字節(jié)形式的 JSON 字符串反序列化同樣簡單。
比如先準(zhǔn)備了一個(gè) JSON 內(nèi)容文件 Person.json。
{
??"name":?"aLang",
??"age":?27,
??"skillList":?[
????"java",
????"c++"
??]
}下面進(jìn)行讀取轉(zhuǎn)換。
ObjectMapper?objectMapper?=?new?ObjectMapper();
@Test
void?testJsonFilePojo()?throws?IOException?{
????File?file?=?new?File("src/Person.json");
????Person?person?=?objectMapper.readValue(file,?Person.class);
??????//?或者
????//?person?=?mapper.readValue(new?URL("http://some.com/api/entry.json"),?MyValue.class);
????System.out.println(person);
????Assertions.assertEquals(person.getName(),?"aLang");
????Assertions.assertEquals(person.getSkillList().toString(),?"[java,?c++]");
}同樣輸出了 Person 內(nèi)容。
Person(name=aLang, age=27, skillList=[java, c++])
JSON 轉(zhuǎn) List
上面演示 JSON 字符串都是單個(gè)對象的,如果 JSON 是一個(gè)對象列表那么使用 Jackson 該怎么處理呢?
已經(jīng)存在一個(gè)文件 PersonList.json.
[
??{
????"name":?"aLang",
????"age":?27,
????"skillList":?[
??????"java",
??????"c++"
????]
??},
??{
????"name":?"darcy",
????"age":?26,
????"skillList":?[
??????"go",
??????"rust"
????]
??}
]讀取它然后轉(zhuǎn)換成 List<Person> 。
ObjectMapper?objectMapper?=?new?ObjectMapper();
@Test
void?fileToPojoList()?throws?IOException?{
????File?file?=?new?File("src/EmployeeList.json");
????List<Person>?personList?=?objectMapper.readValue(file,?new?TypeReference<List<Person>>()?{});
????for?(Person?person?:?personList)?{
????????System.out.println(person);
????}
????Assertions.assertEquals(personList.size(),?2);
????Assertions.assertEquals(personList.get(0).getName(),?"aLang");
????Assertions.assertEquals(personList.get(1).getName(),?"darcy");
}可以輸出對象內(nèi)容:
Person(name=aLang, age=27, skillList=[java, c++])
Person(name=darcy, age=26, skillList=[go, rust])
JSON 轉(zhuǎn) Map
JSON 轉(zhuǎn) Map 在我們沒有一個(gè)對象的 Java 對象時(shí)十分實(shí)用,下面演示如何使用 Jackson 把 JSON 文本轉(zhuǎn)成 Map 對象。
ObjectMapper?objectMapper?=?new?ObjectMapper();
@Test
void?jsonStringToMap()?throws?IOException?{
????String?expectedJson?=?"{\"name\":\"aLang\",\"age\":27,\"skillList\":[\"java\",\"c++\"]}";
????Map<String,?Object>?employeeMap?=?objectMapper.readValue(expectedJson,?new?TypeReference<Map>()?{});
????System.out.println(employeeMap.getClass());
????for?(Entry<String,?Object>?entry?:?employeeMap.entrySet())?{
????????System.out.println(entry.getKey()?+?":"?+?entry.getValue());
????}
????Assertions.assertEquals(employeeMap.get("name"),?"aLang");
}可以看到 Map 的輸出結(jié)果:
class java.util.LinkedHashMap
name:aLang
age:27
skillList:[java, c++]
Jackson 忽略字段
如果在進(jìn)行 JSON 轉(zhuǎn) Java 對象時(shí),JSON 中出現(xiàn)了 Java 類中不存在的屬性,那么在轉(zhuǎn)換時(shí)會遇到 com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException 異常。
使用 objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) 可以忽略不存在的屬性。
ObjectMapper?objectMapper?=?new?ObjectMapper();
@Test
void?jsonStringToPojoIgnoreProperties()?throws?IOException?{
????//?UnrecognizedPropertyException
????String?json?=?"{\"yyy\":\"xxx\",\"name\":\"aLang\",\"age\":27,\"skillList\":[\"java\",\"c++\"]}";
????objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,?false);
????Person?person?=?objectMapper.readValue(json,?Person.class);
??????System.out.printf(person.toString());
????Assertions.assertEquals(person.getName(),?"aLang");
????Assertions.assertEquals(person.getSkillList().toString(),?"[java,?c++]");
}正常輸出:
Person(name=aLang, age=27, skillList=[java, c++])
Jackson 日期格式化
在 Java 8 之前我們通常使用 java.util.Date 類來處理時(shí)間,但是在 Java 8 發(fā)布時(shí)引入了新的時(shí)間類 java.time.LocalDateTime. 這兩者在 Jackson 中的處理略有不同。
先創(chuàng)建一個(gè)有兩種時(shí)間類型屬性的 Order 類。
package?com.wdbyte.jackson;
import?java.time.LocalDateTime;
import?java.util.Date;
import?com.fasterxml.jackson.annotation.JsonFormat;
import?lombok.AllArgsConstructor;
import?lombok.Data;
import?lombok.NoArgsConstructor;
/**
?*?@author?https://www.wdbyte.com
?*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public?class?Order?{
??
????private?Integer?id;
????private?Date?createTime;
????private?LocalDateTime?updateTime;
}
Date 類型
下面我們新建一個(gè)測試用例來測試兩種時(shí)間類型的 JSON 轉(zhuǎn)換。
package?com.wdbyte.jackson;
import?java.time.LocalDateTime;
import?java.util.Date;
import?com.fasterxml.jackson.core.JsonProcessingException;
import?com.fasterxml.jackson.databind.ObjectMapper;
import?org.junit.jupiter.api.Assertions;
import?org.junit.jupiter.api.Test;
/**
?*?@author?https://www.wdbyte.com
?*/
class?OrderTest?{
????ObjectMapper?objectMapper?=?new?ObjectMapper();
????@Test
????void?testPojoToJson0()?throws?JsonProcessingException?{
????????Order?order?=?new?Order(1,?new?Date(),?null);
????????String?json?=?objectMapper.writeValueAsString(order);
????????System.out.println(json);
????????order?=?objectMapper.readValue(json,?Order.class);
????????System.out.println(order.toString());
????????Assertions.assertEquals(order.getId(),?1);
????}
}在這個(gè)測試代碼中,我們只初始化了 Date 類型的時(shí)間,下面是輸出的結(jié)果:
{"id":1,"createTime":1658320852395,"updateTime":null}
Order(id=1, createTime=Wed Jul 20 20:40:52 CST 2022, updateTime=null)
可以看到正常的進(jìn)行了 JSON 的序列化與反序列化,但是 JSON 中的時(shí)間是一個(gè)時(shí)間戳格式,可能不是我們想要的。
LocalDateTime 類型
為什么沒有設(shè)置 LocalDateTime 類型的時(shí)間呢?因?yàn)槟J(rèn)情況下進(jìn)行 LocalDateTime 類的 JSON 轉(zhuǎn)換會遇到報(bào)錯(cuò)。
/**
?*?@author?https://www.wdbyte.com
?*/
class?OrderTest?{
????ObjectMapper?objectMapper?=?new?ObjectMapper();
????@Test
????void?testPojoToJson()?throws?JsonProcessingException?{
????????Order?order?=?new?Order(1,?new?Date(),?LocalDateTime.now());
????????String?json?=?objectMapper.writeValueAsString(order);
????????System.out.println(json);
????????order?=?objectMapper.readValue(json,?Order.class);
????????System.out.println(order.toString());
????????Assertions.assertEquals(order.getId(),?1);
????}
}運(yùn)行后會遇到報(bào)錯(cuò):
com.fasterxml.jackson.databind.exc.InvalidDefinitionException:
Java 8 date/time type `java.time.LocalDateTime` not supported by default:
add Module "com.fasterxml.jackson.datatype:jackson-datatype-jsr310"
to enable handling (through reference chain: com.wdbyte.jackson.Order["updateTime"])
這里我們需要添加相應(yīng)的數(shù)據(jù)綁定支持包。
添加依賴:
<dependency> ????<groupId>com.fasterxml.jackson.datatype</groupId> ????<artifactId>jackson-datatype-jsr310</artifactId> ????<version>2.13.3</version> </dependency>
然后在定義 ObjectMapper 時(shí)通過 findAndRegisterModules() 方法來注冊依賴。
import?java.time.LocalDateTime;
import?java.util.Date;
import?com.fasterxml.jackson.core.JsonProcessingException;
import?com.fasterxml.jackson.databind.ObjectMapper;
import?org.junit.jupiter.api.Assertions;
import?org.junit.jupiter.api.Test;
/**
?*?@author?https://www.wdbyte.com
?*/
class?OrderTest?{
????ObjectMapper?objectMapper?=?new?ObjectMapper().findAndRegisterModules();
????@Test
????void?testPojoToJson()?throws?JsonProcessingException?{
????????Order?order?=?new?Order(1,?new?Date(),?LocalDateTime.now());
????????String?json?=?objectMapper.writeValueAsString(order);
????????System.out.println(json);
????????order?=?objectMapper.readValue(json,?Order.class);
????????System.out.println(order.toString());
????????Assertions.assertEquals(order.getId(),?1);
????}
}運(yùn)行可以得到正常序列化與反序列化日志,不過序列化后的時(shí)間格式依舊奇怪。
{"id":1,"createTime":1658321191562,"updateTime":[2022,7,20,20,46,31,567000000]}
Order(id=1, createTime=Wed Jul 20 20:46:31 CST 2022, updateTime=2022-07-20T20:46:31.567)
時(shí)間格式化
通過在字段上使用注解 @JsonFormat 來自定義時(shí)間格式。
import?java.time.LocalDateTime;
import?java.util.Date;
import?com.fasterxml.jackson.annotation.JsonFormat;
import?lombok.AllArgsConstructor;
import?lombok.Data;
import?lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public?class?Order?{
????private?Integer?id;
????@JsonFormat(pattern?=?"yyyy-MM-dd?HH:mm:ss",?timezone?=?"Asia/Shanghai")
????private?Date?createTime;
????@JsonFormat(pattern?=?"yyyy-MM-dd?HH:mm:ss",?timezone?=?"Asia/Shanghai")
????private?LocalDateTime?updateTime;
}再次運(yùn)行上面的列子可以得到時(shí)間格式化后的 JSON 字符串。
{"id":1,"createTime":"2022-07-20 20:49:46","updateTime":"2022-07-20 20:49:46"}
Order(id=1, createTime=Wed Jul 20 20:49:46 CST 2022, updateTime=2022-07-20T20:49:46)
Jackson 常用注解
@JsonIgnore
使用 @JsonIgnore 可以忽略某個(gè) Java 對象中的屬性,它將不參與 JSON 的序列化與反序列化。
示例:
package?com.wdbyte.jackson;
import?com.fasterxml.jackson.annotation.JsonIgnore;
import?lombok.Data;
/**
?*?@author?https://www.wdbyte.com
?*/
@Data
public?class?Cat?{
????private?String?name;
????@JsonIgnore
????private?Integer?age;
}編寫單元測試類。
package?com.wdbyte.jackson;
import?com.fasterxml.jackson.core.JsonProcessingException;
import?com.fasterxml.jackson.databind.ObjectMapper;
import?org.junit.jupiter.api.Assertions;
import?org.junit.jupiter.api.Test;
/**
?*?@author?https://www.wdbyte.com
?*/
class?CatTest?{
????ObjectMapper?objectMapper?=?new?ObjectMapper();
????@Test
????void?testPojoToJson()?throws?JsonProcessingException?{
????????Cat?cat?=?new?Cat();
????????cat.setName("Tom");
????????cat.setAge(2);
????????String?json?=?objectMapper.writeValueAsString(cat);
????????System.out.println(json);
????????Assertions.assertEquals(json,?"{\"name\":\"Tom\"}");
????????cat?=?objectMapper.readValue(json,?Cat.class);
????????Assertions.assertEquals(cat.getName(),?"Tom");
????????Assertions.assertEquals(cat.getAge(),?null);
????}
}輸出結(jié)果中 age 屬性為 null。
{"name":"Tom"}
@JsonGetter
使用 @JsonGetter 可以在對 Java 對象進(jìn)行 JSON 序列化時(shí)自定義屬性名稱。
import?com.fasterxml.jackson.annotation.JsonGetter;
import?com.fasterxml.jackson.annotation.JsonIgnore;
import?lombok.Data;
/**
?*?@author?https://www.wdbyte.com
?*/
@Data
public?class?Cat?{
????private?String?name;
????private?Integer?age;
????@JsonGetter(value?=?"catName")
????public?String?getName()?{
????????return?name;
????}
}編寫單元測試類進(jìn)行測試。
import?com.fasterxml.jackson.core.JsonProcessingException;
import?com.fasterxml.jackson.databind.ObjectMapper;
import?org.junit.jupiter.api.Assertions;
import?org.junit.jupiter.api.Test;
/**
?*?@author?https://www.wdbyte.com
?*/
class?CatTest?{
????ObjectMapper?objectMapper?=?new?ObjectMapper();
????@Test
????void?testPojoToJson2()?throws?JsonProcessingException?{
????????Cat?cat?=?new?Cat();
????????cat.setName("Tom");
????????cat.setAge(2);
????????String?json?=?objectMapper.writeValueAsString(cat);
????????System.out.println(json);
????????Assertions.assertEquals(json,?"{\"age\":2,\"catName\":\"Tom\"}");
????}
}輸出結(jié)果,name 已經(jīng)設(shè)置成了 catName:
{"age":2,"catName":"Tom"}
@JsonSetter
使用 @JsonSetter 可以在對 JSON 進(jìn)行反序列化時(shí)設(shè)置 JSON 中的 key 與 Java 屬性的映射關(guān)系。
package?com.wdbyte.jackson;
import?com.fasterxml.jackson.annotation.JsonGetter;
import?com.fasterxml.jackson.annotation.JsonIgnore;
import?com.fasterxml.jackson.annotation.JsonSetter;
import?lombok.Data;
/**
?*?@author?https://www.wdbyte.com
?*?@date?2022/07/17
?*/
@Data
public?class?Cat?{
????@JsonSetter(value?=?"catName")
????private?String?name;
????private?Integer?age;
????@JsonGetter(value?=?"catName")
????public?String?getName()?{
????????return?name;
????}
}編寫單元測試類進(jìn)行測試。
import?com.fasterxml.jackson.core.JsonProcessingException;
import?com.fasterxml.jackson.databind.ObjectMapper;
import?org.junit.jupiter.api.Assertions;
import?org.junit.jupiter.api.Test;
/**
?*?@author?https://www.wdbyte.com
?*/
class?CatTest?{
????ObjectMapper?objectMapper?=?new?ObjectMapper();
????@Test
????void?testPojoToJson2()?throws?JsonProcessingException?{
????????String?json?=?"{\"age\":2,\"catName\":\"Tom\"}";
????????Cat?cat?=?objectMapper.readValue(json,?Cat.class);
????????System.out.println(cat.toString());
????????Assertions.assertEquals(cat.getName(),?"Tom");
????}
}輸出結(jié)果:
Cat(name=Tom, age=2)
@JsonAnySetter
使用 @JsonAnySetter 可以在對 JSON 進(jìn)行反序列化時(shí),對所有在 Java 對象中不存在的屬性進(jìn)行邏輯處理,下面的代碼演示把不存在的屬性存放到一個(gè) Map 集合中。
import?java.util.Map;
import?com.fasterxml.jackson.annotation.JsonAnyGetter;
import?com.fasterxml.jackson.annotation.JsonAnySetter;
import?com.google.common.collect.Maps;
import?lombok.AllArgsConstructor;
import?lombok.Data;
import?lombok.NoArgsConstructor;
/**
?*?@author?https://www.wdbyte.com
?*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public?class?Student?{
????private?String?name;
????private?Integer?age;
????private?Map<String,?Object>?diyMap?=?new?HashMap<>();
????@JsonAnySetter
????public?void?otherField(String?key,?String?value)?{
????????this.diyMap.put(key,?value);
????}
}
編寫單元測試用例。
import?java.util.HashMap;
import?java.util.Map;
import?com.fasterxml.jackson.core.JsonProcessingException;
import?com.fasterxml.jackson.databind.ObjectMapper;
import?org.junit.jupiter.api.Assertions;
import?org.junit.jupiter.api.Test;
/**
?*?@author?https://www.wdbyte.com
?*/
class?StudentTest?{
????private?ObjectMapper?objectMapper?=?new?ObjectMapper();
????@Test
????void?testJsonToPojo()?throws?JsonProcessingException?{
????????Map<String,?Object>?map?=?new?HashMap<>();
????????map.put("name",?"aLang");
????????map.put("age",?18);
????????map.put("skill",?"java");
????????String?json?=?objectMapper.writeValueAsString(map);
????????System.out.println(json);
????????Student?student?=?objectMapper.readValue(json,?Student.class);
????????System.out.println(student);
????????Assertions.assertEquals(student.getDiyMap().get("skill"),?"java");
????}
}輸出結(jié)果中可以看到 JSON 中的 skill 屬性因?yàn)椴辉?Java 類 Student 中,所以被放到了 diyMap 集合。
{"skill":"java","name":"aLang","age":18}
Student(name=aLang, age=18, diyMap={skill=java})
@JsonAnyGetter
使用 @JsonAnyGetter 可以在對 Java 對象進(jìn)行序列化時(shí),使其中的 Map 集合作為 JSON 中屬性的來源。下面做個(gè)示例。
import?java.util.HashMap;
import?java.util.Map;
import?com.fasterxml.jackson.annotation.JsonAnyGetter;
import?com.fasterxml.jackson.annotation.JsonAnySetter;
import?com.google.common.collect.Maps;
import?lombok.AllArgsConstructor;
import?lombok.Data;
import?lombok.Getter;
import?lombok.NoArgsConstructor;
import?lombok.Setter;
import?lombok.ToString;
/**
?*?@author?https://www.wdbyte.com
?*/
@ToString
@AllArgsConstructor
@NoArgsConstructor
public?class?Student?{
????@Getter
????@Setter
????private?String?name;
????@Getter
????@Setter
????private?Integer?age;
??
????@JsonAnyGetter
????private?Map<String,?Object>?initMap?=?new?HashMap()?{{
????????put("a",?111);
????????put("b",?222);
????????put("c",?333);
????}};
}編寫單元測試用例。
class?StudentTest?{
????private?ObjectMapper?objectMapper?=?new?ObjectMapper();
????@Test
????void?testPojoToJsonTest()?throws?JsonProcessingException?{
????????Student?student?=?new?Student();
????????student.setName("aLang");
????????student.setAge(20);
????????String?json?=?objectMapper.writeValueAsString(student);
????????System.out.println(json);
??????
???????Assertions.assertEquals(json,"{\"name\":\"aLang\",\"age\":20,\"a\":111,\"b\":222,\"c\":333}");
????}
}輸出結(jié)果:
{"name":"aLang","age":20,"a":111,"b":222,"c":333}
Jackson 總結(jié)
• Jackson 是 Java 中比較流量的 JSON 處理庫之一,它是 Spring 的默認(rèn) JSON 工具。
• Jackson 主要有三個(gè)模塊組成,Streaming API 、Annotations 和 Data Binding 。
• Jackson 中的 ObjectMapper 類十分強(qiáng)大,可以進(jìn)行 JSON 相關(guān)處理,同時(shí)可以結(jié)合注釋以及配置進(jìn)行自定義轉(zhuǎn)換邏輯。
• Jackson 擴(kuò)展性很好,如 CSV、XML、YAML 格式處理都對 Jackson 有相應(yīng)的適配等。
到此這篇關(guān)于利用Jackson解析JSON的詳細(xì)實(shí)現(xiàn)教程的文章就介紹到這了,更多相關(guān)Jackson解析JSON內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java編程用兩個(gè)棧實(shí)現(xiàn)隊(duì)列代碼分享
這篇文章主要介紹了Java編程用兩個(gè)棧實(shí)現(xiàn)隊(duì)列代碼分享,具有一定參考價(jià)值,這里給大家分享下,供需要的朋友了解。2017-10-10
關(guān)于Springboot打成JAR包后讀取外部配置文件的問題
這篇文章主要介紹了關(guān)于Springboot打成JAR包后讀取外部配置文件的問題,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-11-11
Java中的使用及連接Redis數(shù)據(jù)庫(附源碼)
這篇文章主要介紹了Java中的使用及連接Redis數(shù)據(jù)庫(附源碼),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09
java設(shè)計(jì)模式之適配器模式(Adapter)
這篇文章主要介紹了java設(shè)計(jì)模式之適配器模式Adapter的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-01-01
MyBatis注解實(shí)現(xiàn)動態(tài)SQL問題
這篇文章主要介紹了MyBatis注解實(shí)現(xiàn)動態(tài)SQL問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-02-02
springboot項(xiàng)目中添加自定義日志及配置過程
這篇文章主要介紹了springboot項(xiàng)目中添加自定義日志,本文通過示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-07-07

