使用Jackson库实现Java多态解析

Jackson是一个Java的用来处理JSON格式数据的类库,性能非常好。在项目开发中,使用Jackson库的@JsonTypeInfo和@JsonSubTypes注解实现Java多态解析,这里做一个记录。

一、需求背景

在项目开发中,model层的Channel类是一个多态的实现,Channel是一个抽象基类,其有两个子类DatasourceChannel和ServiceChannel。底层的数据库采用MongoDB,因此Channel的所有对象都是在一张表(collection)上的。这样的设计(多态思想)非常优雅,因为只需要面向接口(抽象类)编程而非面向实现(子类)编程。

  • 序列化:Java对象转化为JSON格式数据(而后持久化在数据库中)
  • 反序列化:通过JSON格式数据创建对应的Java对象

在默认的情况下,Java对象和序列化后的JSON格式数据的属性都是一样的。但是在Channel的多态实现下,需要具体的类型信息(子类)指导反序列化(因为两个子类的属性集是不同的)。通过Jackson库的@JsonTypeInfo与@JsonSubTypes注解,可以在序列化时,保存具体的类型信息到JSON数据中,当JSON反序列到Java对象时,就可以根据具体类型信息创建正确的Java对象。

  • @JsonTypeInfo:指明类型信息字段
  • @JsonSubTypes:指明不同类型信息分别对应的子类

二、源代码

1. 抽象基类Channel.java

@Data
@NoArgsConstructor
@Document(collection = "channel")
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXTERNAL_PROPERTY, property = "type")
@JsonSubTypes({
@JsonSubTypes.Type(value = ServiceChannel.class, name = "Service"),
@JsonSubTypes.Type(value = DatasourceChannel.class, name = "DataSource"),
})
@Slf4j
public abstract class Channel {
@Id
protected String id;

@NotBlank
protected String ownerId;

protected List<TransformRule> transformRules;

protected FusionRule fusionRule;

protected String description;

abstract public ChannelDTO convert2DTO();

abstract void doDataDistribution(String message);

public abstract void doCompletion();
}

@JsonTypeInfo指明了类型信息字段为type,@JsonSubTypes指明子类ServiceChannel的类型信息为“Service”,子类DatasourceChannel的类型信息为“DataSource”。

类型信息字段type不属于Channel对象中的属性,它只存在于序列化后的JSON数据中。举个例子,一个普通的ServiceChannel对象序列化为JSON数据时,在JSON数据中会多出一个type属性:*”type” : “Service”*。如果从数据库中拿出这条JSON数据,反序列化为Java对象时,会遵循这个type字段的指导,按照子类ServiceChannel的属性集去构造对应的ServiceChannel对象,而构造成功的ServiceChannel对象中,不会出现该type字段。

2. 子类DatasourceChannel.java

@Data
@NoArgsConstructor
public class DatasourceChannel extends Channel{
@NotBlank
private String datasourceId;

@Builder
public DatasourceChannel(String id, String ownerId, List<TransformRule> transformRules, FusionRule fusionRule, String description, String datasourceId){
super.id = id;
super.ownerId = ownerId;
this.transformRules = transformRules;
this.fusionRule = fusionRule;
this.description = description;
this.datasourceId = datasourceId;
}
}

3. 子类ServiceChannel.java

@Data
@NoArgsConstructor
@Slf4j
public class ServiceChannel extends Channel{
@NotBlank
private String serviceId;

private String serviceName;

@NotBlank
private String apiId;

private String apiPath;

private HttpMethod apiMethod;

@NotBlank
private String datasourceId;

@NotBlank
private String processId;

@Builder
public ServiceChannel(String id, String ownerId, String serviceId, String apiId, List<TransformRule> transformRules, FusionRule fusionRule, String description, String processId, String datasourceId){
super.id = id;
super.ownerId = ownerId;
this.serviceId = serviceId;
this.apiId = apiId;
this.transformRules = transformRules;
this.fusionRule = fusionRule;
this.description = description;
this.processId = processId;
this.datasourceId = datasourceId;
}
}
文章作者: Moon Lou
文章链接: https://loumoon.github.io/2020/09/19/使用Jackson库实现Java多态解析/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Moon's Blog