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 模塊來處理 Avro, BSON, CBOR, CSV, Smile, (Java) Properties, Protobuf, TOML, XML, YAML 這些數(shù)據(jù)編碼,甚至還有大量的數(shù)據(jù)格式模塊,來支持被廣泛使用的數(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常見使用
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 顯示出來的格式美化
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 - 沒有的屬性不會(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串信息值提取出來。主要利用ObjectMapper提供的readTree和Jackson提供的JsonNode類來實(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串以樹狀結(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
在開發(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è)問題,有三種解決方法
- 使用objectMapper.configure(SerializationFeature.xxx,true);把配置補(bǔ)齊
- 設(shè)置自定義類型,加上 @JsonIgnoreProperties 注解,開啟 ignoreUnknown 屬性,以實(shí)現(xiàn)反序列化時(shí)忽略額外的數(shù)據(jù)
- 不要自定義 ObjectMapper,而是直接在配置文件設(shè)置相關(guān)參數(shù),來修改 Spring 默認(rèn)的 ObjectMapper 的功能,例如:spring.jackson.serialization.write_enums_using_index=true
另外,通過查找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);
//把類型信息作為屬性寫入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)文章
SpringBoot整合Elasticsearch并實(shí)現(xiàn)CRUD操作
這篇文章主要介紹了SpringBoot整合Elasticsearch并實(shí)現(xiàn)CRUD操作,需要的朋友可以參考下2018-03-03
Java?zxing實(shí)現(xiàn)生成并解析二維碼與條形碼
這篇文章主要為大家詳細(xì)介紹了Java如何通過zxing實(shí)現(xiàn)生成并解析二維碼與條形碼,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解下2024-11-11
mac下修改idea的jvm運(yùn)行參數(shù)解決idea卡頓的情況
這篇文章主要介紹了mac下修改idea的jvm運(yùn)行參數(shù)解決idea卡頓的情況,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-12-12
Spring Boot實(shí)現(xiàn)模塊化的幾種方法
模塊可以是業(yè)務(wù)模塊,為應(yīng)用程序提供一些業(yè)務(wù)服務(wù),或者為幾個(gè)其他模塊或整個(gè)應(yīng)用程序提供跨領(lǐng)域關(guān)注的技術(shù)模塊。這篇文章主要介紹了Spring Boot實(shí)現(xiàn)模塊化,需要的朋友可以參考下2018-07-07
Java實(shí)現(xiàn)mysql數(shù)據(jù)庫(kù)的自動(dòng)備份和自動(dòng)還原
這篇文章主要為大家詳細(xì)介紹了如何通過Java實(shí)現(xiàn)mysql數(shù)據(jù)庫(kù)的自動(dòng)備份和自動(dòng)還原,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解下2024-11-11
SpringBoot?AnnotationUtils工具類的使用實(shí)例詳解
這篇文章主要介紹了SpringBoot?AnnotationUtils工具類的使用,使用自定義注解標(biāo)記業(yè)務(wù)方法,原生Java獲取注解及AnnotationUtils工具類獲取方法,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2022-09-09
SpringBoot整合EasyExcel實(shí)現(xiàn)批量導(dǎo)入導(dǎo)出
這篇文章主要為大家詳細(xì)介紹了SpringBoot整合EasyExcel實(shí)現(xiàn)批量導(dǎo)入導(dǎo)出功能的相關(guān)知識(shí),文中的示例代碼講解詳細(xì),需要的小伙伴可以參考下2024-03-03

