【问题标题】:How to deserialize JSON with different heirs如何用不同的继承人反序列化 JSON
【发布时间】:2021-07-27 04:23:50
【问题描述】:

json有几种类型,我举两种为例:

{
  "name": "dataUpdated",
  "version": 102,
  "eventTime": "2021-06-24",
  "payload": {
    "id": 158420,
    "name": 446970,
    "date": "2021-06-16",
    "type": "A"
}

{
  "name": "dataError",
  "version": 102,
  "eventTime": "2021-06-25",
  "payload": {
    "error": 666,
    "errorMsg": "forbidden"
}

只有有效载荷的结构发生变化

我有一个 MessageDto 类

class MessageDto {
    
        @JsonProperty("name")
        String name
    
        @JsonProperty("version")
        Integer version
    
        @JsonProperty("eventTime")
        String eventTime
        
        @JsonProperty("payload")
        Payload payload 
    }

Class Payload 是空的,我只是用它作为标记,并从中继承两个类:

DataUpdatedDto extends Payload {

        @JsonProperty("id")
        BigInteger id

        @JsonProperty("name")
        String name

        @JsonProperty("date")
        String date
        
        @JsonProperty("type")
        String type

}

DataErrorDto extends Payload {
    
            @JsonProperty("error")
            Integer error
    
            @JsonProperty("errorMsg")
            String errorMsg
    }

如何向反序列化器解释我想在 Payload 的哪个后代中反序列化?

【问题讨论】:

  • 如果你使用ObjectMapper,它会询问你要反序列化的类
  • 您正在寻找@JsonTypeInfo
  • @chrylis-cautiouslyoptimistic- 如果 JsonTypeName 对所有人都相同,我无法弄清楚如何声明:“有效负载”。要在其中反序列化的类名称的选择取决于属性 MessageDto.name
  • JsonTypeInfo.As.EXTERNAL_PROPERTY 正是针对这种情况的。

标签: java json groovy jackson


【解决方案1】:

您需要设置以下内容:

  • 使用@JsonTypeInfo设置机制来应用一些策略 调度到某些实现类
    • include=JsonTypeInfo.As.EXTERNAL_PROPERTY 因为你想要的 调度不是 inside 有效载荷,而是在同一级别 地图
    • use=JsonTypeInfo.Id.NAME, property="name" 从中读取值 name 属性进行调度
  • @JsonSubTypes@JsonSubTypes.Type 设置一起使用
    • 例如@JsonSubTypes.Type(value=DataUpdatedDto, name="dataUpdated") 将类 DataUpdatedDto 与值相关联 dataUpdated 在父地图内

完整示例

@Grab('com.fasterxml.jackson.core:jackson-databind:2.12.4')
import com.fasterxml.jackson.annotation.*
import com.fasterxml.jackson.databind.*

class MessageDto {

    @JsonProperty("name")
    String name

    @JsonProperty("version")
    Integer version

    @JsonProperty("eventTime")
    String eventTime

    @JsonProperty("payload")
    @JsonTypeInfo(include=JsonTypeInfo.As.EXTERNAL_PROPERTY, use=JsonTypeInfo.Id.NAME, property="name")
    @JsonSubTypes([
            @JsonSubTypes.Type(value=DataUpdatedDto, name="dataUpdated"),
            @JsonSubTypes.Type(value=DataErrorDto, name="dataError")
    ])
    Payload payload 
}

interface Payload {}

class DataUpdatedDto implements Payload {

    @JsonProperty("id")
    BigInteger id

    @JsonProperty("name")
    String name

    @JsonProperty("date")
    String date

    @JsonProperty("type")
    String type

}

class DataErrorDto implements Payload {

    @JsonProperty("error")
    Integer error

    @JsonProperty("errorMsg")
    String errorMsg
}

def objectMapper = new ObjectMapper()
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)

def updated = objectMapper.readValue("""
{
  "name": "dataUpdated",
  "version": 102,
  "eventTime": "2021-06-24",
  "payload": {
    "id": 158420,
    "name": 446970,
    "date": "2021-06-16",
    "type": "A"
  }
}
""", MessageDto)

assert updated.payload instanceof DataUpdatedDto

def error = objectMapper.readValue("""
{
  "name": "dataError",
  "version": 102,
  "eventTime": "2021-06-25",
  "payload": {
    "error": 666,
    "errorMsg": "forbidden"
  }
}
""", MessageDto)

assert error.payload instanceof DataErrorDto

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-12-25
    • 1970-01-01
    • 1970-01-01
    • 2020-09-13
    • 1970-01-01
    • 2018-12-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多