Java中Jackson的序列化與反序列化詳解
一、Jackson簡介
1、什么是Jackson
Jackson被認(rèn)為是"Java JSON庫"或"Java最好的JSON解析器"?;蚝唵蔚乇划?dāng)作"JSON for Java"。不僅如此,Jackson 還是一套用于 Java(和 JVM 平臺)的數(shù)據(jù)處理工具,包括流式 JSON parser / generator庫、匹配 data-binding 庫(POJO和JSON相互轉(zhuǎn)換),還有一個額外的 data format 模塊來處理 Avro, BSON, CBOR, CSV, Smile, (Java) Properties, Protobuf, TOML, XML, YAML 這些數(shù)據(jù)編碼,甚至還有大量的數(shù)據(jù)格式模塊,來支持被廣泛使用的數(shù)據(jù)類型如 Guava, Joda, PCollections 等等
核心組件存在于他們自己的項(xiàng)目下,包括三個核心包(streaming, databind, annotations);數(shù)據(jù)格式庫;數(shù)據(jù)類型庫;JAX-RS provider;和一個復(fù)雜的擴(kuò)展模塊—這個project 連接各個模塊的中心樞紐
2、核心模塊
核心模塊是擴(kuò)展(模塊)構(gòu)建的基礎(chǔ)。目前有3個模塊 (Jackson 2.x為例) :
- Streaming (docs) (“jackson-core”) 定義低級流 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)行各個類型和Json類型的相互轉(zhuǎn)換
1、ObjectMapper的常用配置
private static final ObjectMapper mapper; public static ObjectMapper getObjectMapper(){ return this.mapper; } static{ //創(chuàng)建ObjectMapper對象 mapper = new ObjectMapper() //configure方法 配置一些需要的參數(shù) // 轉(zhuǎn)換為格式化的json 顯示出來的格式美化 mapper.enable(SerializationFeature.INDENT_OUTPUT); //序列化的時候序列對象的那些屬性 //JsonInclude.Include.NON_DEFAULT 屬性為默認(rèn)值不序列化 //JsonInclude.Include.ALWAYS 所有屬性 //JsonInclude.Include.NON_EMPTY 屬性為 空(“”) 或者為 NULL 都不序列化 //JsonInclude.Include.NON_NULL 屬性為NULL 不序列化 mapper.setSerializationInclusion(JsonInclude.Include.ALWAYS); //反序列化時,遇到未知屬性會不會報錯 //true - 遇到?jīng)]有的屬性就報錯 false - 沒有的屬性不會管,不會報錯 mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); //如果是空對象的時候,不拋異常 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")); //處理不同的時區(qū)偏移格式 mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); mapper.registerModule(new JavaTimeModule()); }
2、ObjectMapper的常用方法
2.1 json字符串轉(zhuǎn)對象
ObjectMapper mapper = new ObjectMapper(); String jsonString = "{\"name\":\"shawn\", \"age\":20}"; //將字符串轉(zhuǎn)換為對象 Student student = mapper.readValue(jsonString, Student.class); System.out.println(student); //將對象轉(zhuǎn)換為json字符串 jsonString = mapper.writeValueAsString(student); System.out.println(jsonString);
2.2 數(shù)組和對象之間轉(zhuǎn)換
//對象轉(zhuǎn)為byte數(shù)組 byte[] byteArr = mapper.writeValueAsBytes(student); System.out.println(byteArr); //byte數(shù)組轉(zhuǎn)為對象 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字符串
// 修改時間格式 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這個節(jié)點(diǎn)下的信息 //遍歷results下的信息,size()函數(shù)可以得節(jié)點(diǎn)所包含的的信息的個數(shù),類似于數(shù)組的長度 for(int i=0;i<contents.size();i++) { //讀取節(jié)點(diǎn)下的某個子節(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)用程序時,如果自定義了 ObjectMapper,并把它注冊成了Bean,那很可能會導(dǎo)致 Spring Web 使用的 ObjectMapper 也被替換,導(dǎo)致 Bug。
例如下面的bean,注冊到Spring后就會把Spring原有的配置覆蓋,導(dǎo)致原有的序列化配置丟失
@Bean public ObjectMapper objectMapper(){ ObjectMapper objectMapper=new ObjectMapper(); objectMapper.configure(SerializationFeature.WRITE_ENUMS_USING_INDEX,true); return objectMapper; }
針對這個問題,有三種解決方法
- 使用objectMapper.configure(SerializationFeature.xxx,true);把配置補(bǔ)齊
- 設(shè)置自定義類型,加上 @JsonIgnoreProperties 注解,開啟 ignoreUnknown 屬性,以實(shí)現(xiàn)反序列化時忽略額外的數(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序列化的一個例子
@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)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot整合Elasticsearch并實(shí)現(xiàn)CRUD操作
這篇文章主要介紹了SpringBoot整合Elasticsearch并實(shí)現(xiàn)CRUD操作,需要的朋友可以參考下2018-03-03Java?zxing實(shí)現(xiàn)生成并解析二維碼與條形碼
這篇文章主要為大家詳細(xì)介紹了Java如何通過zxing實(shí)現(xiàn)生成并解析二維碼與條形碼,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解下2024-11-11mac下修改idea的jvm運(yùn)行參數(shù)解決idea卡頓的情況
這篇文章主要介紹了mac下修改idea的jvm運(yùn)行參數(shù)解決idea卡頓的情況,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-12-12Spring Boot實(shí)現(xiàn)模塊化的幾種方法
模塊可以是業(yè)務(wù)模塊,為應(yīng)用程序提供一些業(yè)務(wù)服務(wù),或者為幾個其他模塊或整個應(yīng)用程序提供跨領(lǐng)域關(guān)注的技術(shù)模塊。這篇文章主要介紹了Spring Boot實(shí)現(xiàn)模塊化,需要的朋友可以參考下2018-07-07Java實(shí)現(xiàn)mysql數(shù)據(jù)庫的自動備份和自動還原
這篇文章主要為大家詳細(xì)介紹了如何通過Java實(shí)現(xiàn)mysql數(shù)據(jù)庫的自動備份和自動還原,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解下2024-11-11SpringBoot?AnnotationUtils工具類的使用實(shí)例詳解
這篇文章主要介紹了SpringBoot?AnnotationUtils工具類的使用,使用自定義注解標(biāo)記業(yè)務(wù)方法,原生Java獲取注解及AnnotationUtils工具類獲取方法,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2022-09-09SpringBoot整合EasyExcel實(shí)現(xiàn)批量導(dǎo)入導(dǎo)出
這篇文章主要為大家詳細(xì)介紹了SpringBoot整合EasyExcel實(shí)現(xiàn)批量導(dǎo)入導(dǎo)出功能的相關(guān)知識,文中的示例代碼講解詳細(xì),需要的小伙伴可以參考下2024-03-03