JSON序列化和反序列化還有這種玩法

Mixin對于前端開發(fā)者可不陌生,Vue、React等知名前端框架都使用了Mixin。而對于后端開發(fā),尤其是Java后端開發(fā)來說Mixin卻是一個很陌生的概念。今天來我們通過Jackson讓后端開發(fā)者也來認(rèn)識一下Mixin。
場景
比如我們引用了一個Jar包,其中的某個類在某個場景需要反序列化,但是這個類沒有提供默認(rèn)構(gòu)造。咋辦呢?把原來的項目拉下來,重寫一下?下下策! 你可以使用Jackson提供的Mixin特性來解決這個問題。
Jackson中的Mixin
Jackson中的?Mixin(混入)?我們可以這樣解讀它:將目標(biāo)對象無法實現(xiàn)的序列化或反序列化功能通過一個混入對象進(jìn)行配置,在序列化或反序列化的時候把這些個性化配置混入到目標(biāo)對象中。混入不改變目標(biāo)對象本身的任何特性,混入對象和目標(biāo)對象是映射的關(guān)系。接下來我們來實現(xiàn)一個混入的DEMO。
Mixin的實現(xiàn)
我們有一個User類,為了演示需要,我們極端一些,實際開發(fā)中不太會出現(xiàn)這種極端情況。這個User沒有無參構(gòu)造,也沒有屬性的getter方法。
public?class?User?{
????private?final?String?name;
????private?final?Integer?age;
????public?User(String?name,?Integer?age)?{
????????this.name?=?name;
????????this.age?=?age;
????}
????@Override
????public?String?toString()?{
????????return?"User{"?+
????????????????"name='"?+?name?+?'\''?+
????????????????",?age="?+?age?+
????????????????'}';
????}
}
編寫Mixin類
我想對這個極端的User進(jìn)行序列化和反序列化。按以前的玩法我們在User類上加上@JsonAutoDetect注解就可以實現(xiàn)序列化了;加上@JsonDeserialize注解并指定反序列化類就可以反序列化了。不過今天我們不需要對User進(jìn)行任何更改,只需要編寫一個Mixin類把上述兩個注解配置好就可以了。
@JsonAutoDetect(fieldVisibility?=?JsonAutoDetect.Visibility.ANY,?getterVisibility?=?JsonAutoDetect.Visibility.NONE,
????????isGetterVisibility?=?JsonAutoDetect.Visibility.NONE)
@JsonIgnoreProperties(ignoreUnknown?=?true)
@JsonDeserialize(using?=?UserMixin.UserDeserializer.class)
public?abstract?class?UserMixin?{
????/**
?????*?反序列化類
?????**/
????static?class?UserDeserializer?extends?JsonDeserializer<User>?{
????????@Override
????????public?User?deserialize(JsonParser?p,?DeserializationContext?ctxt)?throws?IOException?{
????????????ObjectMapper?mapper?=?(ObjectMapper)?p.getCodec();
????????????JsonNode?jsonNode?=?mapper.readTree(p);
????????????String?name?=?readJsonNode(jsonNode,?"name").asText(null);
????????????String?age?=?readJsonNode(jsonNode,?"age").asText(null);
????????????Integer?ageVal?=?Objects.isNull(age)??null:?Integer.valueOf(age);
????????????return?new?User(name,ageVal);
????????}
????????private?JsonNode?readJsonNode(JsonNode?jsonNode,?String?field)?{
????????????return?jsonNode.has(field)???jsonNode.get(field)?:?MissingNode.getInstance();
????????}
????}
}
?
其它注解可以參考往期的Jackson文章的介紹
Mixin映射目標(biāo)類
編寫完Mixin類后,我們通過ObjectMapper中的addMixIn方法把UserMixin和User映射起來。并編寫一個序列化和反序列化的例子。
????????ObjectMapper?objectMapper?=?new?ObjectMapper();
????????objectMapper.addMixIn(User.class,?UserMixin.class);
????????User?felord?=?new?User("felord",?12);
????????String?json?=?objectMapper.writeValueAsString(felord);
????????//{"name":"felord","age":12}?
????????System.out.println("json?=?"?+?json);
????????String?jsonStr?=?"{\"name\":\"felord\",\"age\":12}";
????????User?user?=?objectMapper.readValue(jsonStr,?User.class);
????????//?User{name='felord',?age=12}
????????System.out.println("user?=?"?+?user);
這樣我們在不對目標(biāo)類進(jìn)行任何改變的情況下實現(xiàn)了個性化的JSON序列化和反序列化。
Jackson中的Module
Jackson還提供了模塊化功能,可以將個性化配置進(jìn)行模塊化統(tǒng)一管理,而且可以按需引用,甚至可插拔。它同樣能夠管理一組Mixin。聲明一個Jackson Module非常簡單,繼承SimpleModule覆寫它的一些方法即可。針對Mixin我們可以這樣寫:
public?class?UserModule?extends?SimpleModule?{
???public?UserModule()?{
???????super(UserModule.class.getName());
???}
???@Override
???public?void?setupModule(SetupContext?context)?{
????????context.setMixInAnnotations(User.class,UserMixin.class);
???}
}
Module同樣可以注冊到ObjectMapper中,同樣也能實現(xiàn)我們想要的效果:
????????ObjectMapper?objectMapper?=?new?ObjectMapper();
????????objectMapper.registerModule(new?UserModule());
????????//?省略
Module的功能更加強(qiáng)大。平常我們會使用以下幾個Module:
jackson-module-parameter-names?此模塊能夠訪問構(gòu)造函數(shù)和方法參數(shù)的名稱 jackson-datatype-jdk8?除了Java8的時間API外其它新特性的的支持 jackson-datatype-jsr310?用以支持Java8新增的JSR310時間API
另外Spring Security也提供了Module支持SecurityJackson2Modules,它包含了下面的一些模塊:
??????ObjectMapper?mapper?=?new?ObjectMapper();
??????mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL,?JsonTypeInfo.As.PROPERTY);
??????mapper.registerModule(new?CoreJackson2Module());
??????mapper.registerModule(new?CasJackson2Module());
??????mapper.registerModule(new?WebJackson2Module());
??????mapper.registerModule(new?WebServletJackson2Module());
??????mapper.registerModule(new?WebServerJackson2Module());
??????mapper.registerModule(new?OAuth2ClientJackson2Module());
建議看一下SecurityJackson2Modules源碼,研究并模仿一下Module的使用。
2021-11-16

2021-11-15

2021-11-11

2021-11-09

推薦關(guān)注本文作者:碼農(nóng)小胖哥
分享高質(zhì)量編程知識,探討IT人生
