【问题标题】:Deserialize json to subtypes with complex constructor Kotlin + Jackson使用复杂的构造函数 Kotlin + Jackson 将 json 反序列化为子类型
【发布时间】:2021-11-14 08:13:47
【问题描述】:

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

案例一:

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

案例 2:

{
    "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)

是否可以使用 Jackson 反序列化此类结构?

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

【问题讨论】:

  • 试试this guide。如果有帮助,请告诉我。
  • 您好@AliasCartellano,感谢您的回答。提到的指南不包括继承 - 我的情况不是双向关系。

标签: java json kotlin serialization jackson


【解决方案1】:

您缺少一些东西。首先,您需要声明反序列化 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
    )
}

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

@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
    )
}

【讨论】:

  • 感谢您的回答。您的解决方案引入了我试图避免的问题 - 有 20 个孩子,我需要将 Parent (parent1, parent2) 的 20 倍参数复制到孩子的构造函数中,如果需要在 Parent 中引入新参数,我将需要将其添加到 20 个位置。
  • 确实如此,但我不确定您是否可以避免。也许您可以尝试自定义反序列化器,但我会说它并不比这更漂亮。
  • 如果有办法通过一些注释访问原始值,我认为这是可能的:@JsonCreator constructor(@JsonProperty child1: String, @JsonProperty child2: String, @JsonParentTypeSomehow(like original value) parent: Parent)
  • 此外,Jackson 中似乎有一个功能可以让您避免使用type 属性来处理子类型:@JsonTypeInfo(use=Id.DEDUCTION)。从未使用过它,但如果子类型中的字段在它们之间不同,它似乎可以工作,因此杰克逊可以推断它是哪个子类型。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-29
  • 2019-04-29
  • 1970-01-01
  • 1970-01-01
  • 2016-04-15
相关资源
最近更新 更多