Jackson多态序列化图文详解

作者:Looveh 时间:2022-01-26 19:46:08 

场景

做一个消息中心,专门负责发送消息。消息分为几种渠道,包括手机通知(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字段丢失。

Jackson多态序列化图文详解

Jackson多态序列化图文详解

这与我预想的不符,因为客户端知道渠道,构建对应的渠道消息体给我就好了啊!为什么类型被擦除了呢?我的想法就是发送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;
 }
}

Jackson多态序列化图文详解

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

Jackson多态序列化图文详解

Jackson多态序列化图文详解

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

Jackson多态序列化图文详解

来源:https://www.cnblogs.com/lvbok/p/16330663.html

标签:jackson,多态,序列化
0
投稿

猜你喜欢

  • mybatis-plus查询源码详解

    2023-02-02 11:58:02
  • Java swing五子棋的实现方法

    2021-06-01 15:25:20
  • Java数据类型的全面剖析

    2022-07-09 06:51:38
  • Java中String、StringBuffer、StringBuilder的区别介绍

    2023-11-20 18:31:32
  • WPF实现多运算符表达式计算器

    2023-07-17 10:31:40
  • 你都理解创建线程池的参数吗?

    2022-06-10 06:36:05
  • 梳理总结Java static关键字的方法作用

    2023-06-09 04:06:17
  • Java数据结构之ArrayList从顺序表到实现

    2022-06-14 00:53:25
  • java实现抽奖功能解析

    2021-08-29 16:08:21
  • SpringBoot如何在运行时动态添加数据源

    2023-11-13 21:36:40
  • 基于Java语言实现Socket通信的实例

    2021-08-06 17:17:50
  • android TextView设置中文字体加粗实现方法

    2023-08-06 02:32:03
  • Java 如何调用long的最大值和最小值

    2021-07-24 02:27:18
  • java开源好用的简繁转换类库推荐

    2022-11-09 06:31:32
  • java客户端Jedis操作Redis Sentinel 连接池的实现方法

    2023-08-19 10:55:19
  • Java语言实现简单FTP软件 FTP协议分析(1)

    2023-11-10 17:57:21
  • Java项目开发中实现分页的三种方式总结

    2021-08-25 21:36:36
  • Java设计模式之java命令模式详解

    2023-11-13 16:00:36
  • java的泛型你真的了解吗

    2022-07-25 09:40:06
  • 分享我的第一次java Selenium自动化测试框架开发过程

    2021-05-30 01:16:25
  • asp之家 软件编程 m.aspxhome.com