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
相关产品推荐
相关产品推荐

