Java中Jackson的序列化與反序列化詳解
一、Jackson簡(jiǎn)介
1、什么是Jackson
Jackson被認(rèn)為是"Java JSON庫(kù)"或"Java最好的JSON解析器"?;蚝?jiǎn)單地被當(dāng)作"JSON for Java"。不僅如此,Jackson 還是一套用于 Java(和 JVM 平臺(tái))的數(shù)據(jù)處理工具,包括流式 JSON parser / generator庫(kù)、匹配 data-binding 庫(kù)(POJO和JSON相互轉(zhuǎn)換),還有一個(gè)額外的 data format 模塊來(lái)處理 Avro, BSON, CBOR, CSV, Smile, (Java) Properties, Protobuf, TOML, XML, YAML 這些數(shù)據(jù)編碼,甚至還有大量的數(shù)據(jù)格式模塊,來(lái)支持被廣泛使用的數(shù)據(jù)類型如 Guava, Joda, PCollections 等等
核心組件存在于他們自己的項(xiàng)目下,包括三個(gè)核心包(streaming, databind, annotations);數(shù)據(jù)格式庫(kù);數(shù)據(jù)類型庫(kù);JAX-RS provider;和一個(gè)復(fù)雜的擴(kuò)展模塊—這個(gè)project 連接各個(gè)模塊的中心樞紐
2、核心模塊
核心模塊是擴(kuò)展(模塊)構(gòu)建的基礎(chǔ)。目前有3個(gè)模塊 (Jackson 2.x為例) :
- Streaming (docs) (“jackson-core”) 定義低級(jí)流 API,并包括 JSON 具體實(shí)現(xiàn)
- Annotations (docs) (“jackson-annotations”) 包含標(biāo)準(zhǔn) Jackson 注解
- Databind (docs) (“jackson-databind”) 實(shí)現(xiàn)data-binding (和 object serialization) ,支持 streaming 包; 它依賴于 streaming 和 annotations 包
二、ObjectMapper常見(jiàn)使用
ObjectMapper類(com.fasterxml.jackson.databind.ObjectMapper)是Jackson的主要類,它可以幫助我們快速的進(jìn)行各個(gè)類型和Json類型的相互轉(zhuǎn)換
1、ObjectMapper的常用配置
private static final ObjectMapper mapper;
public static ObjectMapper getObjectMapper(){
return this.mapper;
}
static{
//創(chuàng)建ObjectMapper對(duì)象
mapper = new ObjectMapper()
//configure方法 配置一些需要的參數(shù)
// 轉(zhuǎn)換為格式化的json 顯示出來(lái)的格式美化
mapper.enable(SerializationFeature.INDENT_OUTPUT);
//序列化的時(shí)候序列對(duì)象的那些屬性
//JsonInclude.Include.NON_DEFAULT 屬性為默認(rèn)值不序列化
//JsonInclude.Include.ALWAYS 所有屬性
//JsonInclude.Include.NON_EMPTY 屬性為 空(“”) 或者為 NULL 都不序列化
//JsonInclude.Include.NON_NULL 屬性為NULL 不序列化
mapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);
//反序列化時(shí),遇到未知屬性會(huì)不會(huì)報(bào)錯(cuò)
//true - 遇到?jīng)]有的屬性就報(bào)錯(cuò) false - 沒(méi)有的屬性不會(huì)管,不會(huì)報(bào)錯(cuò)
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
//如果是空對(duì)象的時(shí)候,不拋異常
mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
// 忽略 transient 修飾的屬性
mapper.configure(MapperFeature.PROPAGATE_TRANSIENT_MARKER, true);
//修改序列化后日期格式
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
//處理不同的時(shí)區(qū)偏移格式
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
mapper.registerModule(new JavaTimeModule());
}2、ObjectMapper的常用方法
2.1 json字符串轉(zhuǎn)對(duì)象
ObjectMapper mapper = new ObjectMapper();
String jsonString = "{\"name\":\"shawn\", \"age\":20}";
//將字符串轉(zhuǎn)換為對(duì)象
Student student = mapper.readValue(jsonString, Student.class);
System.out.println(student);
//將對(duì)象轉(zhuǎn)換為json字符串
jsonString = mapper.writeValueAsString(student);
System.out.println(jsonString);
2.2 數(shù)組和對(duì)象之間轉(zhuǎn)換
//對(duì)象轉(zhuǎn)為byte數(shù)組 byte[] byteArr = mapper.writeValueAsBytes(student); System.out.println(byteArr); //byte數(shù)組轉(zhuǎn)為對(duì)象 Student student= mapper.readValue(byteArr, Student.class); System.out.println(student); 結(jié)果: [B@3327bd23 Student [ name: shawn, age: 20 ]
結(jié)果:
Student [ name: shawn, age: 20 ]
{
"name" : "Hyl",
"age" : 20
}
2.3 集合和json字符串之間轉(zhuǎn)換
List<Student> studentList= new ArrayList<>();
studentList.add(new Student("shawn1" ,20 , new Date()));
studentList.add(new Student("shawn2" ,21 , new Date()));
studentList.add(new Student("shawn3" ,22 , new Date()));
studentList.add(new Student("shawn4" ,23 , new Date()));
String jsonStr = mapper.writeValueAsString(studentList);
System.out.println(jsonStr);
List<Student> studentList2 = mapper.readValue(jsonStr, List.class);
System.out.println("字符串轉(zhuǎn)集合:" + studentList2 );
結(jié)果:
[ {
"name" : "shawn1",
"age" : 20,
"sendTime" : 1525164212803
}, {
"name" : "shawn2",
"age" : 21,
"sendTime" : 1525164212803
}, {
"name" : "shawn3",
"age" : 22,
"sendTime" : 1525164212803
}, {
"name" : "shawn4",
"age" : 23,
"sendTime" : 1525164212803
} ]
[{name=shawn1, age=20, sendTime=1525164212803}, {name=shawn2, age=21, sendTime=1525164212803}, {name=shawn3, age=22, sendTime=1525164212803}, {name=shawn4, age=23, sendTime=1525164212803}]
2.4 map和json字符串之間轉(zhuǎn)換
Map<String, Object> testMap = new HashMap<>();
testMap.put("name", "22");
testMap.put("age", 20);
testMap.put("date", new Date());
testMap.put("student", new Student("shawn", 20, new Date()));
String jsonStr = mapper.writeValueAsString(testMap);
System.out.println(jsonStr);
Map<String, Object> testMapDes = mapper.readValue(jsonStr, Map.class);
System.out.println(testMapDes);
結(jié)果:
{
"date" : 1525164212803,
"name" : "22",
"student" : {
"name" : "shawn",
"age" : 20,
"sendTime" : 1525164212803,
"intList" : null
},
"age" : 20
}
{date=1525164212803, name=22, student={name=shawn, age=20, sendTime=1525164212803, intList=null}, age=20}
2.5 日期轉(zhuǎn)json字符串
// 修改時(shí)間格式
mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
Student student = new Student ("shawn",21, new Date());
student.setIntList(Arrays.asList(1, 2, 3));
String jsonStr = mapper.writeValueAsString(student);
System.out.println(jsonStr);
結(jié)果:
{
"name" : "shawn",
"age" : 21,
"sendTime" : "2020-07-23 13:14:36",
"intList" : [ 1, 2, 3 ]
}
2.6 readTree()方法
此方法更靈活,可以只將用戶感興趣的Json串信息值提取出來(lái)。主要利用ObjectMapper提供的readTree和Jackson提供的JsonNode類來(lái)實(shí)現(xiàn)
String test="{"results":[{"objectID":357,"geoPoints":[{"x":504604.59802246094,"y":305569.9150390625}]},{"objectID":358,"geoPoints":[{"x":504602.2680053711,"y":305554.43603515625}]}]}";
//此Json串比較復(fù)雜,包含了嵌套數(shù)組的形式,具有通用性。
//2.2.2.2實(shí)現(xiàn)反序列化
JsonNode node= objectMapper.readTree(test); //將Json串以樹(shù)狀結(jié)構(gòu)讀入內(nèi)存
JsonNode contents=node.get("results");//得到results這個(gè)節(jié)點(diǎn)下的信息
//遍歷results下的信息,size()函數(shù)可以得節(jié)點(diǎn)所包含的的信息的個(gè)數(shù),類似于數(shù)組的長(zhǎng)度
for(int i=0;i<contents.size();i++) {
//讀取節(jié)點(diǎn)下的某個(gè)子節(jié)點(diǎn)的值
System.out.println(contents.get(i).get("objectID").getIntValue());
JsonNode geoNumber=contents.get(i).get("geoPoints");
//循環(huán)遍歷子節(jié)點(diǎn)下的信息
for(int j=0;j<geoNumber.size();j++){
System.out.println(geoNumber.get(j).get("x").getDoubleValue()+" "+geoNumber.get(j).get("y").getDoubleValue());
}
}
3、Java Web與ObjectMapper
在開(kāi)發(fā) Spring Web 應(yīng)用程序時(shí),如果自定義了 ObjectMapper,并把它注冊(cè)成了Bean,那很可能會(huì)導(dǎo)致 Spring Web 使用的 ObjectMapper 也被替換,導(dǎo)致 Bug。
例如下面的bean,注冊(cè)到Spring后就會(huì)把Spring原有的配置覆蓋,導(dǎo)致原有的序列化配置丟失
@Bean
public ObjectMapper objectMapper(){
ObjectMapper objectMapper=new ObjectMapper();
objectMapper.configure(SerializationFeature.WRITE_ENUMS_USING_INDEX,true);
return objectMapper;
}
針對(duì)這個(gè)問(wèn)題,有三種解決方法
- 使用objectMapper.configure(SerializationFeature.xxx,true);把配置補(bǔ)齊
- 設(shè)置自定義類型,加上 @JsonIgnoreProperties 注解,開(kāi)啟 ignoreUnknown 屬性,以實(shí)現(xiàn)反序列化時(shí)忽略額外的數(shù)據(jù)
- 不要自定義 ObjectMapper,而是直接在配置文件設(shè)置相關(guān)參數(shù),來(lái)修改 Spring 默認(rèn)的 ObjectMapper 的功能,例如:spring.jackson.serialization.write_enums_using_index=true
另外,通過(guò)查找JacksonProperties類源碼,可以發(fā)現(xiàn)很多配置類的屬性,可以配合使用
4、Redis序列化的一個(gè)例子
@Bean
public <T> RedisTemplate<String, T> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, T> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.enable(DeserializationFeature.USE_LONG_FOR_INTS);
//把類型信息作為屬性寫(xiě)入Value
objectMapper.activateDefaultTyping(objectMapper.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
redisTemplate.setKeySerializer(RedisSerializer.string());
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setHashKeySerializer(RedisSerializer.string());
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}到此這篇關(guān)于Java中Jackson的序列化與反序列化詳解的文章就介紹到這了,更多相關(guān)Jackson的序列化與反序列化內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java多線程知識(shí)點(diǎn)全面總結(jié)
這篇文章主要介紹了Java多線程知識(shí)點(diǎn)全面總結(jié),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03
springboot反爬蟲(chóng)組件kk-anti-reptile的使用方法
這篇文章主要介紹了springboot反爬蟲(chóng)組件kk-anti-reptile的使用方法,幫助大家更好的利用spring boot反爬蟲(chóng),保護(hù)網(wǎng)站安全,感興趣的朋友可以了解下2021-01-01
利用Jacob將Excel轉(zhuǎn)換PDF的問(wèn)題匯總
項(xiàng)目中經(jīng)常會(huì)遇到將excel轉(zhuǎn)換成PDF的需求,下面這篇文章主要給大家介紹了關(guān)于如何利用Jacob將Excel轉(zhuǎn)換PDF問(wèn)題的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-05-05
Arthas-java程序運(yùn)行時(shí)debug工具使用
這篇文章主要介紹了Arthas-java程序運(yùn)行時(shí)debug工具使用,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-11-11
Mybatis-plus設(shè)置某個(gè)字段值為null的方法總結(jié)
mybatis-plus以下簡(jiǎn)稱mp,目前應(yīng)該也算是主流的一款數(shù)據(jù)訪問(wèn)層應(yīng)用框架,下面這篇文章主要給大家介紹了關(guān)于Mybatis-plus設(shè)置某個(gè)字段值為null的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-07-07
Java?注解@PostConstruct的原理及最佳使用場(chǎng)景分析
@PostConstruct?是?Java?中非常實(shí)用的注解,尤其是在?Spring?等框架中,它使得開(kāi)發(fā)者可以方便地在?Bean?初始化后執(zhí)行額外的操作,本文給大家介紹@PostConstruct?的原理、使用場(chǎng)景及最佳實(shí)踐,感興趣的朋友一起看看吧2025-04-04
Spring Boot MyBatis 操作數(shù)據(jù)庫(kù)的實(shí)戰(zhàn)指南
本文詳細(xì)介紹了SpringBoot環(huán)境下MyBatis的集成與應(yīng)用,從傳統(tǒng)JDBC的局限性出發(fā),展示了MyBatis的日志配置、CRUD操作、自增主鍵返回、多表查詢等功能,感興趣的朋友跟隨小編一起看看吧2026-05-05

