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

Mixin對(duì)于前端開發(fā)者可不陌生,Vue、React等知名前端框架都使用了Mixin。而對(duì)于后端開發(fā),尤其是Java后端開發(fā)來(lái)說Mixin卻是一個(gè)很陌生的概念。今天來(lái)我們通過Jackson讓后端開發(fā)者也來(lái)認(rèn)識(shí)一下Mixin。
場(chǎng)景
比如我們引用了一個(gè)Jar包,其中的某個(gè)類在某個(gè)場(chǎng)景需要反序列化,但是這個(gè)類沒有提供默認(rèn)構(gòu)造。咋辦呢?把原來(lái)的項(xiàng)目拉下來(lái),重寫一下?下下策! 你可以使用Jackson提供的Mixin特性來(lái)解決這個(gè)問題。
Jackson中的Mixin
Jackson中的?Mixin(混入)?我們可以這樣解讀它:將目標(biāo)對(duì)象無(wú)法實(shí)現(xiàn)的序列化或反序列化功能通過一個(gè)混入對(duì)象進(jìn)行配置,在序列化或反序列化的時(shí)候把這些個(gè)性化配置混入到目標(biāo)對(duì)象中?;烊氩桓淖兡繕?biāo)對(duì)象本身的任何特性,混入對(duì)象和目標(biāo)對(duì)象是映射的關(guān)系。接下來(lái)我們來(lái)實(shí)現(xiàn)一個(gè)混入的DEMO。
Mixin的實(shí)現(xiàn)
我們有一個(gè)User類,為了演示需要,我們極端一些,實(shí)際開發(fā)中不太會(huì)出現(xiàn)這種極端情況。這個(gè)User沒有無(wú)參構(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類
我想對(duì)這個(gè)極端的User進(jìn)行序列化和反序列化。按以前的玩法我們?cè)?code style="font-size: 14px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(53, 179, 120);background-color: rgba(27, 31, 35, 0.05);word-break: break-all;">User類上加上@JsonAutoDetect注解就可以實(shí)現(xiàn)序列化了;加上@JsonDeserialize注解并指定反序列化類就可以反序列化了。不過今天我們不需要對(duì)User進(jìn)行任何更改,只需要編寫一個(gè)Mixin類把上述兩個(gè)注解配置好就可以了。
@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映射起來(lái)。并編寫一個(gè)序列化和反序列化的例子。
????????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);
這樣我們?cè)诓粚?duì)目標(biāo)類進(jìn)行任何改變的情況下實(shí)現(xiàn)了個(gè)性化的JSON序列化和反序列化。
Jackson中的Module
Jackson還提供了模塊化功能,可以將個(gè)性化配置進(jìn)行模塊化統(tǒng)一管理,而且可以按需引用,甚至可插拔。它同樣能夠管理一組Mixin。聲明一個(gè)Jackson Module非常簡(jiǎn)單,繼承SimpleModule覆寫它的一些方法即可。針對(duì)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同樣可以注冊(cè)到ObjectMapper中,同樣也能實(shí)現(xiàn)我們想要的效果:
????????ObjectMapper?objectMapper?=?new?ObjectMapper();
????????objectMapper.registerModule(new?UserModule());
????????//?省略
Module的功能更加強(qiáng)大。平常我們會(huì)使用以下幾個(gè)Module:
jackson-module-parameter-names?此模塊能夠訪問構(gòu)造函數(shù)和方法參數(shù)的名稱 jackson-datatype-jdk8?除了Java8的時(shí)間API外其它新特性的的支持 jackson-datatype-jsr310?用以支持Java8新增的JSR310時(shí)間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ì)量編程知識(shí),探討IT人生
