一、问题背景

Jackson框架对json字段的序列化和反序列化默认策略是根据getter和setter方法,去掉get和set,再把首字母小写,便找到了对应的字段。通常情况,我们都是对普通的POJO进行serialization/deserialization。那么如果遇到了解析抽象类(或者接口)呢?如何定位到对应的实现类?实现类都找不到,谈何匹配到对应的字段反序列化。

二、JsonTypeInfo 注解简单介绍

作用于类或接口,被用来处理多态类型的序列化及反序列化。

This is necessarily for polymorphic types, and may also be needed to link abstract declared types and matching concrete implementation.

三、demo

先写个小demo对这个功能有个初步的感性认识。

1.抽象类

package jackson;import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import lombok.Data;@Data
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type", visible = true)
@JsonSubTypes({@JsonSubTypes.Type(value = InputPageModel.class, name = "input"), @JsonSubTypes.Type(value = NumberPageModel.class, name = "number")})
public abstract class Page {private String type;private String name;private String uiType;private String label;
}

注解里的visible字段:如果为false,那么反序列化时,类型id字段(在这个demo里是type字段)的值将不会被反序列化到POJO中。

2.1 实现类1

package jackson;import lombok.Data;@Data
public class InputPage extends Page {private String input;
}

2.2 实现类2

package jackson;import lombok.Data;@Data
public class NumberPage extends Page {private Integer number;
}

3.测试类

package jackson;import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;import java.io.IOException;public class JsonTypeInfoTest {public static void main(String[] args) {String inputJson = " {\n" +"        \"type\": \"input\",\n" +"        \"label\": \"标题\",\n" +"        \"uiType\": \"input\",\n" +"        \"input\" : \"lvsheng\"\n" +"        \n" +"      }";ObjectMapper mapper = new ObjectMapper();try {InputPage inputPageModel = ((InputPage) mapper.readValue(inputJson, Page.class));System.out.println(inputPageModel.getInput());} catch (IOException e) {e.printStackTrace();}String numberJson = " {\n" +"        \"type\": \"number\",\n" +"        \"label\": \"价格\",\n" +"        \"uiType\": \"input\",\n" +"        \"number\" : 110\n" +"        \n" +"      }";try {NumberPage numberPageModel = ((NumberPage) mapper.readValue(numberJson, Page.class));System.out.println(numberPageModel.getNumber());} catch (IOException e) {e.printStackTrace();}}
}

测试类输出

lvsheng
110

四、 在大型工程里的应用

这个demo里JsonTypeInfo借助JsonSubTypes注解来感知抽象类的有哪些实现类,并且是如何匹配的。在大型工程中抽象类的子类很多(接口的实现很多),那么JsonSubTypes注解就十分臃肿了。而且这种写法是 违反开闭原则(OCP) 的。借助以下方式可以将JsonSubTypes剔除掉,达到相同的效果。

1. 给子类加JsonTypeName注解

package jackson;import com.fasterxml.jackson.annotation.JsonTypeName;
import lombok.Data;@Data
@JsonTypeName(value = "input")
public class InputPage extends Page {private String input;
}

2. 借助reflections框架,将所有JsonTypeName注解类扫描出来

ObjectMapper并不具备扫描实现JsonTypeName注解的类,因此需要自己手工扫描所有带有这个注解的类。reflections框架在我的另一篇博客 Reflections框架,类扫描神器 里有介绍。

Set<Class<?>> classSet = reflections.getTypesAnnotatedWith(JsonTypeName.class);

3. 手工将扫出来的类注册到ObjectMapper对象

最后一步,完成子类注册

ObjectMapper  mapper   = new ObjectMapper();
classSet.parallelStream().forEach(clazz -> mapper.registerSubtypes(clazz));

这样便可以在大型工程里优雅的使用jackson解析多态类,每增加一个子类型,无需修改额外的代码。对扩展开放,对修改封闭。

五、其他主流json框架对多态的支持

框架 是否支持 备注
gson 支持 不支持注解,使用不方便 官方demo
fastjson 不支持
json-lib 不支持

当遇到json框架技术选型时,如果有处理多态的需求,那么jackson无疑是最佳的选择。


附录

jackson github 主页地址 https://github.com/FasterXML/jackson

借助Jackson的JsonTypeInfo注解实现多态类的解析相关推荐

  1. Jackson之JSON序列化和多态反序列化

    SerDe是Serialize/Deserilize的简称,即序列化和反序列化. 一.Jackson之序列化和反序列化 JSON作为一种轻量级的数据交换格式,其清晰和简洁的结构能够轻松地与Java对象 ...

  2. Jackson 通过自定义注解来控制json key的格式

    Jackson 通过自定义注解来控制json key的格式 最近我这边有一个需求就是需要把Bean中的某一些特殊字段的值进行替换.而这个替换过程是需要依赖一个第三方的dubbo服务的.为了使得这个转换 ...

  3. ssm注解配置连接mysql_基于注解和配置类的SSM(Spring+SpringMVC+Mybatis)项目详细配置...

    在上一篇文章中介绍了使用注解和xml配置文件对项目进行配置,在这篇文章中将xml配置文件中的配置信息都改成使用注解或者配置类的形式. 第一步.配置pom.xml 在一个ssm项目中,可能需要用到的依赖 ...

  4. Jackson 序列化 自定义注解处理Null 值

    目录 问题引入 解决问题 查看 @JsonSerialize(nullsUsing = StringNullSerializer.class) nullsUsing 的实现逻辑 自定义注解解决问题 如 ...

  5. 【Jackson】@JsonCreator 注解

    该注解用在对象的反序列时指定特定的构造函数或者工厂方法.在反序列化时,Jackson默认会调用对象的无参构造函数,如果我们不定义任何构造函数,Jvm会负责生成默认的无参构造函数.但是如果我们定义了构造 ...

  6. AnnotationConfigUtils 处理注解Bean 定义类中的通用注解

    AnnotationConfigUtils 类的processCommonDefinitionAnnotations()在向容器注册Bean 之前,首先对注解Bean 定义类中的通用Spring 注解 ...

  7. java aop注解拦截_Spring AOP 拦截指定注解标识的类或方法

    代码Demo @Aspect @Component @Order(10) public class BidAuthorityProxy { /** * 扫描指定包下的类中使用@EnableRoleAu ...

  8. 【Android 安全】DEX 加密 ( Proguard keep 用法 | Proguard 默认混淆结果 | 保留类及成员混淆结果 | 保留注解以及被注解修饰的类/成员/方法 )

    文章目录 一.Proguard 默认混淆结果 二.Proguard 保留类及成员混淆结果 三.Proguard 保留注解以及被注解修饰的类/成员/方法 更多 ProGuard 混淆配置参考 : htt ...

  9. Spring MVC框架:第二章:视图解析器和@RequestMapping注解使用在类级别及获取原生Servlet API对象

    SpringMVC使用细节 第一节 视图解析器 通过HelloWorld程序我们看到了handler方法的返回值表示: 请求处理完成后,请SpringMVC执行一个请求转发.转发的地址就是handle ...

最新文章

  1. python下载大文件-python-Django:允许用户下载大文件
  2. java 自动拆箱_Java 自动装箱 和 自动拆箱
  3. java forward 修改请求参数_聊聊springboot session timeout参数设置
  4. java上传png_java上传png图片出现红色背景
  5. nagios远程系统监测服务
  6. 蓝色企业CMS网站后台管理模板
  7. python 读取数据库内存爆_解决python读取几千万行的大表内存问题
  8. 批量图片处理,打包成zip
  9. 阿里云智能基础产品事业部招聘高性能计算云产品研发与优化专家/高级专家
  10. 杨中科:【我的大学生活】
  11. 排序算法(天勤数据结构高分笔记)
  12. 大数据课程30天掌握 spark内存计算(python )-徐培成-专题视频课程
  13. 管理型工业以太网交换机什么
  14. 全面拆解携程云原生实践,打造智能弹性的云端酒店直连系统
  15. ubuntu默认开启numlock
  16. Shell脚本介绍(资源)
  17. 怎样把网上的短信发送到手机
  18. mysql1291错误_当MySQL创建表格时出现 1291 - Column 'e_sxe' has duplicated value '?' in ENUM 错误...
  19. 《数字图像处理》题库5:计算题 ①
  20. python 智禅_禅道是什么意思:非禅不智,非智不禅

热门文章

  1. 如何取消隐藏文件扩展名
  2. pandas使用read_csv函数读取文件的前N行数据并保留表头、pandas使用read_csv函数读取制表符分割的文件(tab-delimited)、自定义设置sep参数
  3. 在线房屋收租app开发优势
  4. python 使用h5py 中遇到的问题
  5. h3c linux驱动 wn612_安装Ubuntu双系统系列——64位Ubuntu安装H3C的INode客户端
  6. clion 产生sigabrt_OpenNERO Ubuntu:进程结束,退出代码134(被信号6:SIGABRT中断)
  7. Sicily 1031. Campus
  8. windows状态栏里显示实时网速
  9. win10怎么新建计算机用户,Win10添加用户教程(Microsoft微软帐户、本地帐户、儿童帐户)...
  10. 归因分析:淘宝直播数据助理及其价值研究