前几天遇到个问题,场景大概是 list 中既有父类又有子类,在反序列化时丢掉了子类的信息。解决这个问题也没花多少时间,不过还是打算记录下。参考链接如下:

Jackson JSON - Using @JsonTypeInfo annotation to handle polymorphic types

我使用 Jackson 实现序列化和反序列化。它在处理多态序列化时的思路是,构造一个起到标识作用的成员变量,并将该成员变量序列化到最终的字符串中,这样在反序列化的时候,jackson一看到这个标识符就知道该朝着哪个类进行反序列化了。

场景

父类:

public abstract class Shape {}

两个子类:

@Data
@ToString
public class Circle extends Shape {int radius;public static Circle of(int radius){Circle circle = new Circle();circle.setRadius(radius);return circle;}}
@Data
@ToString
public class Rectangle extends Shape {private int w;private int h;public static Rectangle of(int w, int h) {Rectangle rectangle = new Rectangle();rectangle.setH(h);rectangle.setW(w);return rectangle;}
}

构建 list:

@Data
@ToString
public class View {private List<Shape> shapes;
}

序列化与反序列化的代码:

public class MainExample {public static void main(String[] args) throws Exception {View view = new View();view.setShapes(new ArrayList<Shape>() {{add(Rectangle.of(3, 6));add(Circle.of(5));}});System.out.println("---- serializing ---");ObjectMapper om = new ObjectMapper();String s = om.writeValueAsString(view);System.out.println(s);System.out.println("--- deserializing ---");View view1 = om.readValue(s,View.class);System.out.println(view1);}

它序列化以及反序列化后的结果:

---- serializing ---
{"shapes":[{"className":"rectangle1","w":3,"h":6},{"className":"circle1","radius":5}]}
--- deserializing ---
View(shapes=[Rectangle(w=3, h=6), Circle(radius=5)])

很明显,无论是 Rectangle 还是 Circle,在序列化后除了自己本省的属性对应的键值对外,各自都多了一个键值对,这个多出来的就是写进的子类信息。靠多出来的这个键值对,就可以保障反序列化的结果是正确的。

正如开头提及的,Jackson是将子列的信息写到了序列化后的字符串中,那具体是怎么写的呢?

它是这么写的:

@JsonTypeInfo(use = Id.NAME, include = As.PROPERTY, property = "className" ,visible = false)public abstract class Shape {}

@JsonTypeInfo:Json类型信息,@JsonSubTypes : Json子类型。纠结这两个准确的意思很没有意思,也不是很必要,必要的是这两个货后面跟着的括弧中的那帮玩意到底表示什么。

@JsonTypeInfo(use = Id.NAME, include = As.PROPERTY, property = "className" ,visible = false)
@JsonSubTypes({@JsonSubTypes.Type(value = Rectangle.class, name = "rectangle1"),@JsonSubTypes.Type(value = Circle.class, name = "circle1")
})

这两个注解干了一件这样的事情:

include = As.PROPERTY 表示在 Shape 中添加一个成员变量(这个成员变量其实充当了一个类型标识符的作用),父类里面有这个变量,子类当然也就继承到了;property = "className" 表示这个成员变量的名字叫“className”,当然你可以写成别的阿猫阿狗;visible = false 表示“className”这个成员变量在反序列化的时候要被“剔除”掉,也就是说该属性不参与反序列化;use = Id.NAME 表示成员变量className对应的值由用户自己定义,只要不重复就行。那这个值到底是什么呢,@JsonSubTypes.Type(value = Rectangle.class, name = "rectangle1") 表示 Rectangle 的实例中成员变量className 的值是rectangle1Circle 也是同样的表示方式。

所以就出现可这样的序列化结果:

---- serializing ---
{"shapes":[{"className":"rectangle1","w":3,"h":6},{"className":"circle1","radius":5}]}

子类的类型信息被“塞到”序列化后的字符串中。

放反序列化的时候,jackson 一看到 rectangle1 就知道这个json字符串要向 Rectangle.class 反序列化,看到 circle1 就向 Circle.class 反序列化。说白了,就是在序列化后的json字符串中添加了一个具有标志作用的键值对,Jackson通过这个键值对确定json应该朝着那个类反序列化。

稍稍变一丢丢

先看啊,序列化的字符串中多了个键值对(虽说反序列化时又给去掉了),假如我要将序列化后的字符串保存起来,mybatis中存json的场景在开发中可是经常会出现的,对象序列化后平白无故多了一些信息,而且还給保存下来了,总归觉得有点别扭。

我着实遇到过这样的场景:创建的 List<object> 需要持久化到 MySQL,并且还要返回给前端。持久化要求序列化和反序列化必须成功。返回给前端要求序列化后不能出现多余的键值对。

如何既能不多信息,又能保证多态反序列化结果正确呢?很简单,在类中找到一个字段,要求不同子类中这个字段的值是不一样的,甚至子类和父类中这个字段的值也是不一样的,拿这个字段作为反序列化的区分标志就行了。

上面的场景改一下:

@Data
@ToString
public class Circle extends Shape {int radius;private String type = "CIR";public static Circle of(int radius){Circle circle = new Circle();circle.setRadius(radius);return circle;}}
@Data
@ToString
public class Rectangle extends Shape {private int w;private int h;private String type = "REC";public static Rectangle of(int w, int h) {Rectangle rectangle = new Rectangle();rectangle.setH(h);rectangle.setW(w);return rectangle;}
}
@JsonTypeInfo(use = Id.NAME, include = As.EXISTING_PROPERTY, property = "type" ,visible = true)
@JsonSubTypes({@JsonSubTypes.Type(value = Rectangle.class, name = "REC"),@JsonSubTypes.Type(value = Circle.class, name = "CIR")
})
public abstract class Shape {}

序列化与反序列化结果:

---- serializing ---
{"shapes":[{"w":3,"h":6,"type":"REC"},{"radius":5,"type":"CIR"}]}
--- deserializing ---
View(shapes=[Rectangle(w=3, h=6, type=REC), Circle(radius=5, type=CIR)])

至于过程这个自己分析啦,很简单的。

jackson多态序列化与反序列化相关推荐

  1. java为什么序列化不一致_java – 为什么Jackson多态序列化在列表中不起作用?

    杰克逊正在做一些真正奇怪的事情,我找不到任何解释.我正在进行多态序列化,当一个对象独立时它可以很好地工作.但是,如果将相同的对象放入列表并对列表进行序列化,则会删除类型信息. 它丢失类型信息的事实将导 ...

  2. Jackson 自定义序列化和反序列化

    目录 1. 创建序列化类 2. 创建反序列化类 3. 实体类字段添加注解 4. 反序列操作 5. 序列化操作 1. 创建序列化类 继承JsonSerializer或者StdSerializer,添加泛 ...

  3. hutol json null值没了_JSON数据处理框架Jackson精解第一篇-序列化与反序列化核心用法...

    Jackson是Spring Boot默认的JSON数据处理框架,但是其并不依赖于任何的Spring 库.有的小伙伴以为Jackson只能在Spring框架内使用,其实不是的,没有这种限制.它提供了很 ...

  4. jackson (json、xml的序列化与反序列化)

    jackson用于java对象到json的序列化与反序列化.还支持xml格式. jackson用于实现json与java对象的序列与反序列化.web service要实现跨机器传送对象那么就需要有一种 ...

  5. jackson 序列化_jackson序列化与反序列化的应用实践

    作者 | zhouweixin 来源 | urlify.cn/iEbiAz 66套java从入门到精通实战课程分享 1 相关概念 序列化: 把对象转换为字节序列的过程称为对象的序列化 反序列化: 把字 ...

  6. Jackson序列化和反序列化

    1,下载Jackson工具包(jackson-core-2.2.3.jar  jackson-annotations-2.2.3.jar  jackson-databind-2.2.3.jar ) j ...

  7. jackson驼峰转下划线注解_jackson序列化与反序列化的应用实践

    作者 | zhouweixin 来源 | urlify.cn/iEbiAz 66套java从入门到精通实战课程分享 1 相关概念 序列化: 把对象转换为字节序列的过程称为对象的序列化 反序列化: 把字 ...

  8. Jackson对泛型的序列化和反序列化方法汇总

    转载自:https://www.cnblogs.com/EasonJim/p/7919422.html 说明:Jackson对于简单泛型是可以正常操作的,但是如果对于太过于复杂的泛型类有时会不成功.目 ...

  9. 程序验证Jackson反序列化的规则、Jackson序列化与反序列化关键方法程序详细分析

    目录 0. 为什么要做这个分析 1. Jackson反序列化时,无参构造.有参构造的执行顺序[附程序截图] 1.1 没有无参构造时: 1.2 无参构造和有参构造方法都有的时候先走无参构造: 2. Ja ...

最新文章

  1. Kinect for windows的脸部识别
  2. html5 jq图片效果,HTML5 jQuery可左右滑动拖拉的照片处理前后对比界面
  3. iOS瀑布流实现(Swift)
  4. mongodb php 扩展 linux,CentOS Linux 安装PHP的MongoDB扩展
  5. 《飞鸽传书》把写程序和文学创作相提并论
  6. Redis-列表(List)基础
  7. 输入一批整数,输出最大最小值,输入0结束
  8. Android 中的MVP 模式
  9. 注意一些坑,从app跳转到qq聊天界面。
  10. 广义典型相关分析_数学建模/机器学习:广义加性模型(GAM)及其Python实现
  11. java 类的继承 例题_Java_接口与类之间继承例题
  12. 人证合一验证目前逐渐普及大众
  13. 织梦登陆总是提示验证码错误
  14. 用proteus实现STM32仿真
  15. linux 内核 mtd读取,linux内核 mtd分区
  16. 2023年全国最新交安安全员精选真题及答案4
  17. 户外风景拍摄自然风光摄影网站搭建模板
  18. 我的日本友人(二):清野先生
  19. 数商云采购管理系统方案助力采购平台:缩短采购周期、降本增效
  20. 知到网课艺术中国真题题库分享(含答案)

热门文章

  1. 【教程+源码】Java开发经典游戏飞翔的小鸟_Java游戏项目Flappy Bird像素鸟游戏
  2. 一月三万用户,我的迅载网盘运营经验
  3. Windows Server 2019 安装oracle11g
  4. 搜狗输入法如何java_java - 如何获取搜狗输入法的词库
  5. Typora 常用快捷键使用汇总
  6. mid是什么音乐文件?为什么这么小?
  7. 营销CRM软件(销售管理工具)让客户都成为回头客
  8. 6-4 结构体-查找最低分
  9. 国内优秀开源电商项目评测、PHP版和Java版都有开源
  10. 【BIOS大全】释义+设置+精解+释疑————玩转电脑必备工具帖(9)