我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Jackson多态序列化图文详解

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Jackson多态序列化图文详解

场景

做一个消息中心,专门负责发送消息。消息分为几种渠道,包括手机通知(Push)、短信(SMS)、邮件(Email),Websocket等渠道。

我定义了一个基类MessageRequest用来接收请求参数,代码如下:

public class MessageRequest implements Serializable {
  protected MessageChannel channel;
  private MessageRequest(){}
  protected MessageRequest(MessageChannel channel){
    this.channel = channel;
  }
  
  public MessageChannel getChannel() {
    return this.channel;
  }
}

MessageRequest中有个属性channel是枚举MessageChannel,该枚举列举所有渠道,代码如下:

public enum MessageChanne {
  PUSH,
  EMAIL,
  WEBSOCKET,
  SMS,
  ;
  
  MessageChannel() {}
}

MessageRequest有各种渠道的子类实现,以Push为例:

public class PushMessageReuqest extends MessageRequest {
  public PushMessageRequest() {
    super(MessageChannel.PUSH);
  }
  
  private String title;
  // 省略其他字段以及getter、setter方法
  ...
}

我在接口入参使用MessageRequest接收:

public class MessageController {
  @PostMapping("/sendMessage")
  public R<Object> sendMessage(MessageRequest request) {
    System.out.println(request);
  }
}

使用postman发送push请求之后发现后端收到的类型还是基类,并且title字段丢失。

这与我预想的不符,因为客户端知道渠道,构建对应的渠道消息体给我就好了啊!为什么类型被擦除了呢?我的想法就是发送push请求啊。。。。。后来才知道序列化之后在反序列化的时候不知道给你反序列化成什么类型,序列化工具也没有聪明到能根据你的channel属性就知道是什么类型,但是我又想这样做。那么怎么办呢????

Jackson多态类型序列化/反序列化

经过查询资料以及咨询了一下领导,发现了@JsonTypeInfo@JsonSubTypes两个注解。

@JsonTypeInfo作用于类/接口,被用来开启多态类型处理,它有一些属性:

  • use(必选):定义使用哪一种类型标识码,有以下几个可选项。
    • NONE:不使用识别码
    • CLASS:使用完全限定类名做识别码
    • MINIMAL_CLASS:使用类名(忽略包名)做识别码,和基类在同一个包可用
    • NAME:指定名称
    • CUSTOM:自定义识别码,由@JsonTypeIdResolver对应
  • include(可选):指定识别码如何被包含进去,有以下几个可选项。
    • PROPERTY:作为兄弟属性加入,默认值
    • WRAPPER_OBJECT:作为一个包装的对象
    • WRAPPER_ARRAY:作为包装的数组
    • EXTERNAL_PROPERTY:作为扩展属性
    • EXISTING_PROPERTY:作为已存在的属性(符合我的场景,用channel)
  • property(可选):指定识别码的属性名称。该属性只有当use为CLASS(不指定默认为@class)、MINIMAL_CLASS(不指定默认为@c)、NAME(不指定默认为@typeinclude为PROPERTY、EXISTING_PROPERTY、EXTERNAL_PROPERTY时才有效。
  • defaultImpl(可选):如果类型识别码不存在或者无效,可以使用该属性来指定反序列化时使用的默认类型。
  • visible(可选,默认false):属性定义了类型标识符是否会成为反序列化器的一部分,默认为false,也就是说Jackson会从json内容中删除类型标识再传递给JsonDeserializer。

@JsonSubTypes作用于类/接口,用来列出给定类/接口的子类。一般配合@JsonTypeInfo使用

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "channel")
@JsonSubTypes({
  @JsonSubTypes.Type(value = PushMessageRequest.class, name = "PUSH"),
  @JsonSubTypes.Type(value = EmailMessageRequest.class, name = "EMAIL")
})

JsonSubTypes的值是一个@JsonSubTypes.Type[]数组,参数value表示类型,参数name表示@JsonTypeInfo注解中property属性的值,对比以上代码即:channel = "PUSH"或channel = "EMAIL"。name为可选值,不指定时需在子类提供JsonTypeName注解并指定value属性。

实战

改造上面提供的MessageReuqest

// include默认为PROPERTY,这里可以不加
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "channel")
@JsonSubTypes({
  @JsonSubTypes.Type(value = PushMessageRequest.class, name = "PUSH"),
  @JsonSubTypes.Type(value = EmailMessageRequest.class, name = "EMAIL")
})
public class MessageRequest implements Serializable {
  
  protected MessageChannel channel;
  
  private MessageRequest(){}
  
  protected MessageRequest(MessageChannel channel){
    this.channel = channel;
  }
  
  public MessageChannel getChannel() {
    return this.channel;
  }
}

此时通过postman请求发现入参类型有了变化

include属性使用默认的PROPERTY时发现序列化之后的json会多出来一个属性,属性名对应的就是@JsonTypeInfoproperty的值。虽然不影响使用,但是我看着很不舒服。基于我这种情况可以使用include=EXISTING_PROPERTY

总结

到此这篇关于Jackson多态序列化的文章就介绍到这了,更多相关Jackson多态序列化内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Jackson多态序列化图文详解

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Jackson多态序列化怎么实现

这篇文章主要介绍“Jackson多态序列化怎么实现”,在日常操作中,相信很多人在Jackson多态序列化怎么实现问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Jackson多态序列化怎么实现”的疑惑有所帮助!
2023-07-02

jackson多态反序列化怎么实现

在Jackson中,实现多态反序列化可以使用@JsonTypeInfo注解和@JsonSubTypes注解。首先,在父类上使用@JsonTypeInfo注解,指定多态类型的字段名和默认的多态类型处理策略。例如:@JsonTypeInfo(
2023-10-22

Java利用Jackson序列化实现数据脱敏详解

在项目中有些敏感信息不能直接展示,比如客户手机号、身份证、车牌号等信息,展示时均需要进行数据脱敏,防止泄露客户隐私。本文将利用Jackson序列化实现数据脱敏,需要的可以参考一下
2023-05-13

一文详解Java对象的序列化和反序列化

本文主要介绍了一文详解Java对象的序列化和反序列化,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
2023-05-16

Vue3中动态修改样式与级联样式优先顺序图文详解

在项目中,我们时常会遇到动态的去绑定操作切换不同的CSS样式,下面这篇文章主要给大家介绍了关于Vue3中动态修改样式与级联样式优先顺序的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
2023-05-16

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录