前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JSON序列化和反序列化还有这种玩法

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

作者头像
码农小胖哥
发布2021-11-19 14:10:44
1.3K0
发布2021-11-19 14:10:44
举报

Mixin对于前端开发者可不陌生,Vue、React等知名前端框架都使用了Mixin。而对于后端开发,尤其是Java后端开发来说Mixin却是一个很陌生的概念。今天来我们通过Jackson让后端开发者也来认识一下Mixin

场景

比如我们引用了一个Jar包,其中的某个类在某个场景需要反序列化,但是这个类没有提供默认构造。咋办呢?把原来的项目拉下来,重写一下?下下策! 你可以使用Jackson提供的Mixin特性来解决这个问题。

Jackson中的Mixin

Jackson中的Mixin(混入)我们可以这样解读它:将目标对象无法实现的序列化或反序列化功能通过一个混入对象进行配置,在序列化或反序列化的时候把这些个性化配置混入到目标对象中。混入不改变目标对象本身的任何特性,混入对象和目标对象是映射的关系。接下来我们来实现一个混入的DEMO。

Mixin的实现

我们有一个User类,为了演示需要,我们极端一些,实际开发中不太会出现这种极端情况。这个User没有无参构造,也没有属性的getter方法。

代码语言:javascript
复制
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进行序列化和反序列化。按以前的玩法我们在User类上加上@JsonAutoDetect注解就可以实现序列化了;加上@JsonDeserialize注解并指定反序列化类就可以反序列化了。不过今天我们不需要对User进行任何更改,只需要编写一个Mixin类把上述两个注解配置好就可以了。

代码语言:javascript
复制
@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映射目标类

编写完Mixin类后,我们通过ObjectMapper中的addMixIn方法把UserMixinUser映射起来。并编写一个序列化和反序列化的例子。

代码语言:javascript
复制
        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);

这样我们在不对目标类进行任何改变的情况下实现了个性化的JSON序列化和反序列化。

Jackson中的Module

Jackson还提供了模块化功能,可以将个性化配置进行模块化统一管理,而且可以按需引用,甚至可插拔。它同样能够管理一组Mixin。声明一个Jackson Module非常简单,继承SimpleModule覆写它的一些方法即可。针对Mixin我们可以这样写:

代码语言:javascript
复制
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中,同样也能实现我们想要的效果:

代码语言:javascript
复制
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.registerModule(new UserModule());
        // 省略

Module的功能更加强大。平常我们会使用以下几个Module:

  • jackson-module-parameter-names 此模块能够访问构造函数和方法参数的名称
  • jackson-datatype-jdk8 除了Java8的时间API外其它新特性的的支持
  • jackson-datatype-jsr310 用以支持Java8新增的JSR310时间API

另外Spring Security也提供了Module支持SecurityJackson2Modules,它包含了下面的一些模块:

代码语言:javascript
复制
      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-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 码农小胖哥 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 场景
  • Jackson中的Mixin
  • Mixin的实现
    • 编写Mixin类
      • Mixin映射目标类
        • Jackson中的Module
        相关产品与服务
        文件存储
        文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档