当前位置: 首页 > 科技观察

Json序列化和反序列化还有这种玩法

时间:2023-03-14 12:57:32 科技观察

Mixin对于前端开发者来说并不陌生。Vue、React等知名的前端框架都使用了Mixin。对于后端开发,尤其是Java后端开发,Mixin是一个非常陌生的概念。今天,我们让后端开发者通过Jackson来认识Mixin。场景比如我们引用了一个Jar包,里面的一个类在某个场景下需要反序列化,但是这个类并没有提供默认的结构体。我应该怎么办?把原来的工程拉下来重写?一个坏主意!可以使用Jackson提供的Mixin特性来解决这个问题。Jackson中的Mixin杰克逊中的Mixin(混入),我们可以这样解读:通过一个混合对象配置目标对象无法实现的序列化或反序列化功能,在序列化或反序列化时将这些个性化的配置混入目标中目的。mix-in不会改变目标对象本身的任何特性,mix-in对象与目标对象是映射关系。接下来我们来实现一个混入的DEMO。对于Mixin的实现,我们有一个User类。为了演示,我们说的有点极端,实际开发中不太可能出现这种极端情况。此User没有无参数结构,也没有属性getter方法。publicclassUser{privatefinalStringname;privatefinalIntegerage;publicUser(Stringname,Integerage){this.name=name;this.age=age;}@OverridepublicStringtoString(){return"User{"+"name='"+name+'\''+",age="+age+'}';}}编写Mixin类我要序列化和反序列化这个极端的User。按照之前的玩法,我们可以在User类中添加@JsonAutoDetect注解来实现序列化;添加@JsonDeserialize注解,指定反序列化类进行反序列化。但是今天我们不需要对User做任何改动,只需要写一个Mixin类来配置上??面两个注解即可。@JsonAutoDetect(fieldVisibility=JsonAutoDetect.Visibility.ANY,getterVisibility=JsonAutoDetect.Visibility.NONE,isGetterVisibility=JsonAutoDetect.Visibility.NONE)@JsonIgnoreProperties(ignoreUnknown=true)@JsonDeserialize(using=UserMixin.UserDeserializer.class)*反序列化类**/staticclassUserDeserializerextendsJsonDeserializer{@OverridepublicUserdeserialize(JsonParserp,DeserializationContextctxt)throwsIOException{ObjectMappermapper=(ObjectMapper)p.getCodec();JsonNodejsonNode=mapper.readTree(p);Stringname=readJsonNode(jsonNode,"name").asText(null);Stringage=readJsonNode(jsonNode,"age").asText(null);IntegerageVal=Objects.isNull(age)?null:Integer.valueOf(age);returnnewUser(name,ageVal);}privateJsonNodereadJsonNode(JsonNodejsonNode,Stringfield){returnjsonNode.has(field)?jsonNode.get(field):MissingNode.getInstance();}}}其他的注解可以参考之前Jackson文章Mixin映射目标类的介绍,写好Mixin类后,我们添加UserMixin通过ObjectMapper中的addMixIn方法MapwithUser,写一个序列化和反序列化的例子。ObjectMapperobjectMapper=newObjectMapper();objectMapper.addMixIn(User.class,UserMixin.class);Userfelord=newUser("felord",12);Stringjson=objectMapper.writeValueAsString(felord);//{"name":"felord","age":12}System.out.println("json="+json);StringjsonStr="{\"name\":\"felord\",\"age\":12}";Useruser=objectMapper。readValue(jsonStr,User.class);//用户{name='felord',age=12}System.out.println("user="+user);这样,我们就可以在不修改目标类的情况下实现个性化的JSON序列化和反序列化。Jackson中的ModuleJackson也提供了模块化的功能,可以模块化统一管理个性化配置,可以按需引用甚至可插拔。它还可以管理一组混合。声明一个JacksonModule非常简单,只需继承SimpleModule并重写它的一些方法即可。对于Mixin,我们可以这样写:同样注册在ObjectMapper中,我们也可以实现我们想要的效果:ObjectMapperobjectMapper=newObjectMapper();objectMapper.registerModule(newUserModule());//省略Module的功能更强大。通常我们会用到以下模块:jackson-module-parameter-names这个模块可以访问构造函数和方法参数的名称jackson-datatype-jdk8除了Java8的timeAPI,jackson-datatype还支持其他新特性-jsr310为了支持Java8新的JSR310时间API,SpringSecurity还提供了Module来支持SecurityJackson2Modules,包括以下模块:ObjectMappermapper=newObjectMapper();mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL,JsonTypeInfo.As.PROPERTY);mapper.registerModule(newCoreJackson2Module());mapper.registerModule(newCasJackson2Module());mapper.registerModule(newWebJackson2Module());mapper.registerModule(newWebServletJackson2Module());mapper.registerModule(newWebServerJackson2Module());mapper.registerson2Client2Client2Module(newOAuth());建议查看SecurityJackson2Modules的源码,学习模仿Module的使用。