java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Jackson多态序列化

Jackson多态序列化图文详解

作者:Looveh

jackson允许配置多态类型处理,当进行反序列话时,JSON数据匹配的对象可能有多个子类型,为了正确的读取对象的类型,我们需要添加一些类型信息,下面这篇文章主要给大家介绍了关于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作用于类/接口,被用来开启多态类型处理,它有一些属性:

@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多态序列化内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文