Java的Jackson自定義序列化詳解
Jackson自定義序列化
本篇簡單寫寫Jackson中自定義序列化的方式。
假設(shè)有類Country和Leader,分別表示國家以及國家領(lǐng)導(dǎo)人,領(lǐng)導(dǎo)人除了姓名外還有年齡和民族,定義如下
@Data @NoArgsConstructor @AllArgsConstructor public class Country { private String countryName; private Leader leader; }
@Data @NoArgsConstructor @AllArgsConstructor public class Leader { private String leaderName; private Integer age; private String nation; }
基于上述定義,且看下面的代碼輸出結(jié)果結(jié)果
@Test void test5() throws JsonProcessingException { ObjectMapper objectMapper = new ObjectMapper(); Country country = new Country("元朝", new Leader("忽必烈", 79, "蒙古族")); System.out.println(objectMapper.writeValueAsString(country)); }
輸出結(jié)果
{"countryName":"元朝","leader":{"leaderName":"忽必烈","age":79,"nation":"蒙古族"}}
可以看到,正常的序列化方式會將leader的屬性都進行序列化。
然而,有些時候,我們并不需要關(guān)心這個國家的領(lǐng)導(dǎo)人的詳細信息,我們只需要知道他叫什么名字即可,例如我們想在序列化之后輸入如下的JSON,那就需要定制序列化方式。
1、自定義序列化器
首先定義一個序列化器,繼承自Serializer類或其子類
import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.ser.std.StdSerializer; import java.io.IOException; public class LeaderSerializer extends StdSerializer<Leader> { public LeaderSerializer() { this(null); } protected LeaderSerializer(Class<Leader> t) { super(t); } @Override public void serialize(Leader value, JsonGenerator gen, SerializerProvider provider) throws IOException { if (value == null) { gen.writeNull(); return; } // 直接輸入領(lǐng)導(dǎo)人姓名,不需要起始和結(jié)束的花括號 gen.writeString(value.getLeaderName()); } }
有了序列化,自然需要反序列化
import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.deser.std.StdDeserializer; import java.io.IOException; public class LeaderDeserializer extends StdDeserializer<Leader> { public LeaderDeserializer() { this(null); } protected LeaderDeserializer(Class<?> vc) { super(vc); } @Override public Leader deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException { String leaderName = p.getValueAsString(); if (leaderName == null) { return null; } return getLeaderByName(leaderName); } private Leader getLeaderByName(String leaderName) { // TODO 查詢數(shù)據(jù)庫或通過其他操作返回leader詳細信息 if ("忽必烈".equals(leaderName)) { Leader leader = new Leader(); leader.setLeaderName(leaderName); leader.setAge(79); leader.setNation("蒙古族"); return leader; } return null; } }
然后應(yīng)用序列化類,在leader屬性上添加序列化和反序列化注解。
注意,不能添加在Leader類上,否則會改變Leader類的默認序列化和反序列化方式,這里序列化的目標依舊是Country
@Data @NoArgsConstructor @AllArgsConstructor public class Country { private String countryName; @JsonSerialize(using = LeaderSerializer.class) @JsonDeserialize(using = LeaderDeserializer.class) private Leader leader; }
測試
@Test void test6() throws JsonProcessingException { ObjectMapper objectMapper = new ObjectMapper(); Leader leader = new Leader("忽必烈", 79, "蒙古族"); Country country = new Country("元朝", leader); System.out.println(objectMapper.writeValueAsString(leader)); System.out.println(objectMapper.writeValueAsString(country)); }
輸出結(jié)果
{"leaderName":"忽必烈","age":79,"nation":"蒙古族"}
{"countryName":"元朝","leader":"忽必烈"}
從輸出結(jié)果可以看到,Leader的序列化方式依舊是正常的,但是Country中的leader屬性序列化后輸出的只有l(wèi)eaderName屬性,已經(jīng)實現(xiàn)了我們需要的功能。
再來測試反序列化
@Test void test7() throws JsonProcessingException { ObjectMapper objectMapper = new ObjectMapper(); String json = "{\"countryName\":\"元朝\",\"leader\":\"忽必烈\"}"; System.out.println(objectMapper.readValue(json, Country.class)); }
輸出結(jié)果
Country(countryName=元朝, leader=Leader(leaderName=忽必烈, age=79, nation=蒙古族))
可以看到,結(jié)果也是正常的。
2、使用@JsonValue和@JsonCreator注解
首先將上面Country中l(wèi)eader屬性上加的序列化注解和反序列化注解去掉,還原為最初,然后修改Leader類如下
@Data @NoArgsConstructor @AllArgsConstructor public class Leader { @JsonValue private String leaderName; private Integer age; private String nation; @JsonCreator(mode = JsonCreator.Mode.DELEGATING) public static Leader getLeaderByName(String leaderName) { // TODO 查詢數(shù)據(jù)庫或通過其他操作返回leader詳細信息 if ("忽必烈".equals(leaderName)) { Leader leader = new Leader(); leader.setLeaderName(leaderName); leader.setAge(79); leader.setNation("蒙古族"); return leader; } return null; } }
注意:@JsonCreator注解所標注的類必須要是static的
再來執(zhí)行上面的測試類test6(),輸出結(jié)果如下
"忽必烈"
{"countryName":"元朝","leader":"忽必烈"}
對比序列化器,可以看到,使用@JsonValue注解已經(jīng)將Leader類的序列化方式改變了,進而影響了Country類。再來執(zhí)行test7()測試反序列化,結(jié)果與之前是一致的。但是執(zhí)行下面的反序列化測試的時候卻報了錯,從報錯信息可以看到是JSON識別錯誤,暫時還未找到解決方法,待后續(xù)補充完善。
@Test void test8() throws JsonProcessingException { ObjectMapper objectMapper = new ObjectMapper(); System.out.println(objectMapper.readValue("忽必烈", Leader.class)); }
com.fasterxml.jackson.core.JsonParseException: Unrecognized token '忽必烈': was expecting (JSON String, Number, Array, Object or token 'null', 'true' or 'false') at [Source: (String)"忽必烈"; line: 1, column: 4]
所以更推薦使用自定義序列化器和反序列化器的方式來實現(xiàn)。
到此這篇關(guān)于Java的Jackson自定義序列化詳解的文章就介紹到這了,更多相關(guān)Jackson自定義序列化內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue3實現(xiàn)多頁面跳轉(zhuǎn)效果的幾種方式
Vue.js是一個用于構(gòu)建用戶界面的漸進式 JavaScript 框架,它提供了多種方法來實現(xiàn)頁面之間的導(dǎo)航,在 Vue 3 中,頁面跳轉(zhuǎn)主要通過 Vue Router 來管理,同時也支持其他方式如編程式導(dǎo)航和使用錨點鏈接,本文將詳細介紹 Vue 3 中的各種頁面跳轉(zhuǎn)方式,需要的朋友可以參考下2025-03-03springboot+mybatis快速插入大量數(shù)據(jù)的具體實現(xiàn)
最近導(dǎo)入表格數(shù)據(jù)時需要同時插入修改大量數(shù)據(jù),下面這篇文章主要給大家介紹了關(guān)于springboot+mybatis快速插入大量數(shù)據(jù)的具體實現(xiàn),文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下2023-04-04Springboot通過谷歌Kaptcha?組件生成圖形驗證碼功能
Kaptcha是谷歌開源的一款簡單實用的圖形驗證碼組件。我個人推薦它的最大原因是容易上手,采用約定大于配置的方式,快速契合到項目中,這篇文章主要介紹了Springboot通過谷歌Kaptcha組件生成圖形驗證碼的方法,需要的朋友可以參考下2023-05-05SpringCloud中NacosNamingService的作用詳解
這篇文章主要介紹了SpringCloud中NacosNamingService的作用詳解,NacosNamingService類完成服務(wù)實例注冊,撤銷與獲取服務(wù)實例操作,NacosNamingService初始化采用單例模式,使用反射生成,需要的朋友可以參考下2023-11-11java使用CollectionUtils工具類判斷集合是否為空方式
這篇文章主要介紹了java使用CollectionUtils工具類判斷集合是否為空方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-02-02