首页 > 解决方案 > 使用复杂的构造函数 Kotlin + Jackson 将 json 反序列化为子类型

问题描述

我正在使用 kotlin 和 jackson,我正在寻找一种方法来反序列化具有以下结构的 json,这可能在两种情况下有所不同:

情况1:

{
    "parent1": "parentvalue1",
    "parent2": "parentvalue2",
    "child1": "childvalue1",
    "child2": "childvalue2"
}

案例二:

{
    "parent1": "parentvalue1",
    "parent2": "parentvalue2",
    "child3": "childvalue3",
    "child4": "childvalue4"
}

我的模型类如下所示:

家长:

open class Parent(
    val parent1: String,
    val parent2: String
) {
    constructor (parent: Parent) : this(
        parent1 = parent.parent1,
        parent2 = parent.parent2
    )
}

孩子们:

class Child1(
    parent: Parent,
    val child1: String,
    val child2: String
) : Parent(parent)

class Child2(
    parent: Parent,
    val child3: String,
    val child4: String
) : Parent(parent)

使用杰克逊反序列化这种结构是否可行?

val parent = ObjectMapper().readValue(myJson, Parent::class.java)

标签: javajsonkotlinserializationjackson

解决方案


您缺少一些东西。首先,您需要声明反序列化 JSON 时要使用的构造函数,您所拥有的构造函数与 JSON 格式不匹配:

class Child1(
    parent: Parent,
    val child1: String,
    val child2: String
) : Parent(parent) {
  
  @JsonCreator constructor (parent1: String, parent2: String, child1: String, child2: String) {
      super(parent1, parent2)
      child1 = child1
      child2 = child2
  )
}

然后,您还需要告诉杰克逊如何区分Child1Child2。你可以这样做:

@JsonTypeInfo(
  use = JsonTypeInfo.Id.NAME, 
  include = JsonTypeInfo.As.PROPERTY, 
  property = "type")
@JsonSubTypes(
  JsonSubTypes.Type(value = Child1::class, name = "child1"), 
  JsonSubTypes.Type(value = Child2::class, name = "child2") 
)
open class Parent(
    val parent1: String,
    val parent2: String
) {
    constructor (parent: Parent) : this(
        parent1 = parent.parent1,
        parent2 = parent.parent2
    )
}

在您的情况下,您甚至可以使用以下内容,因为子类型中的字段在它们之间是不同的,因此杰克逊可以推断它是哪个子类型:

@JsonTypeInfo(use=Id.DEDUCTION)
@JsonSubTypes(
  JsonSubTypes.Type(value = Child1::class, name = "child1"), 
  JsonSubTypes.Type(value = Child2::class, name = "child2") 
)
open class Parent(
    val parent1: String,
    val parent2: String
) {
    constructor (parent: Parent) : this(
        parent1 = parent.parent1,
        parent2 = parent.parent2
    )
}

推荐阅读