You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin+Jackson如何实现带复杂构造函数的子类型JSON反序列化

实现方案

是可以实现的,Jackson从2.12版本开始支持按JSON字段特征自动推断子类型的能力,无需在JSON中新增额外的类型标识字段,具体配置步骤如下:


1. 引入必要依赖

首先确保项目引入了Jackson对Kotlin的支持模块,否则无法正确解析Kotlin类的构造函数参数:

// Gradle 依赖示例
implementation "com.fasterxml.jackson.module:jackson-module-kotlin:2.15.2" // 版本和你用的Jackson核心版本一致即可

2. 给父类添加子类型推断注解

给Parent类加上@JsonTypeInfo和@JsonSubTypes注解,开启自动类型推导:

import com.fasterxml.jackson.annotation.JsonSubTypes
import com.fasterxml.jackson.annotation.JsonTypeInfo

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

Id.DEDUCTION配置会让Jackson自动根据JSON中存在的字段,匹配对应子类型的独有属性,完成反序列化。


3. 调整子类构造函数适配反序列化

把原有子类的构造函数调整为直接接收父类属性,避免Jackson需要额外构造Parent实例:

class Child1(
    // 直接声明父类属性传递给父类构造
    parent1: String,
    parent2: String,
    val child1: String,
    val child2: String
) : Parent(parent1, parent2)

class Child2(
    parent1: String,
    parent2: String,
    val child3: String,
    val child4: String
) : Parent(parent1, parent2)

4. 初始化ObjectMapper并测试

初始化ObjectMapper时注册Kotlin模块,之后就可以直接按你给出的写法反序列化:

import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.KotlinModule
import com.fasterxml.jackson.module.kotlin.readValue

fun main() {
    val objectMapper = ObjectMapper()
        .registerModule(KotlinModule.Builder().build()) // Jackson 2.13以下版本直接写KotlinModule()

    // 测试Case1
    val case1Json = """
        {
            "parent1": "parentvalue1",
            "parent2": "parentvalue2",
            "child1": "childvalue1",
            "child2": "childvalue2"
        }
    """.trimIndent()
    val parent1 = objectMapper.readValue<Parent>(case1Json)
    println(parent1 is Child1) // 输出true

    // 测试Case2
    val case2Json = """
        {
            "parent1": "parentvalue1",
            "parent2": "parentvalue2",
            "child3": "childvalue3",
            "child4": "childvalue4"
        }
    """.trimIndent()
    val parent2 = objectMapper.readValue<Parent>(case2Json)
    println(parent2 is Child2) // 输出true
}

注意事项

  • 两个子类的独有字段不能有重叠,否则Jackson无法区分类型会抛出异常
  • 如果使用的Jackson版本低于2.12,不支持Id.DEDUCTION特性,可以自定义StdDeserializer<Parent>实现:先将JSON解析为JsonNode,判断节点中是否存在child1/child2或child3/child4字段,再手动映射为对应子类实例即可
  • 如果要保留原有子类接收Parent实例的构造写法,可以给构造函数加上@JsonCreator注解,配合@JacksonInject注入Parent实例,不过调整构造函数的方式更简单易维护

内容的提问来源于stack exchange,提问作者arturk9

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 07:48:04