如何使用Jackson解析Kotlin双泛型密封类Response?
双泛型密封类Jackson解析问题的解决方案
问题描述
定义了用于表示网络响应状态的双泛型密封类Response,代码如下:
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "status") @JsonSubTypes( value = [ JsonSubTypes.Type(value = Response.OK::class, name = "OK"), JsonSubTypes.Type(value = Response.Error::class, name = "ERROR"), ] ) sealed class Response<out Content, out Error> { data class OK<out Content>(val content: Content) : Response<Content, Nothing>() data class Error<out Error>(val error: Error) : Response<Nothing, Error>() }
网络响应JSON根据status字段区分结构:
status="OK"时包含content字段,对应Response.OKstatus="ERROR"时包含error字段,对应Response.Error
但解析时抛出错误:
Could not resolve type id 'OK' as a subtype of `com.example.models.Response<java.lang.String,java.lang.String>`: Failed to specialize base type com.example.models.Response<java.lang.String,java.lang.String> as com.example.models.Response$OK, problem: Type parameter #1/2 differs; can not specialize java.lang.String with java.lang.Object at [Source: (String)"{ "status": "OK", "content": "Hello" }"; line: 2, column: 13]
错误原因
Jackson解析子类型时无法协变匹配父类的双泛型参数:
Response.OK继承的是Response<Content, Nothing>,但解析时指定的目标类型是Response<String, String>,第二个泛型参数不匹配(NothingvsString)- 类型擦除加上协变泛型的特性,导致Jackson无法完成父类到子类的类型特化
解决方案
方案1:调整子类泛型声明,对齐父类双泛型
修改子类的泛型定义,让每个子类都携带父类的两个泛型参数(即使其中一个用Nothing占位),确保Jackson能正确匹配类型参数:
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "status") @JsonSubTypes( value = [ JsonSubTypes.Type(value = Response.OK::class, name = "OK"), JsonSubTypes.Type(value = Response.Error::class, name = "ERROR"), ] ) sealed class Response<out Content, out Error> { data class OK<out Content, out Error>(val content: Content) : Response<Content, Nothing>() data class Error<out Content, out Error>(val error: Error) : Response<Nothing, Error>() }
方案2:使用TypeReference明确指定泛型类型
解析时用TypeReference替代reified泛型,避免类型擦除导致的泛型信息丢失:
@Test fun `parses OK response`() { val json = """ { "status": "OK", "content": "Hello" } """.trimIndent() val result = objectMapper.readValue(json, object : TypeReference<Response<String, String>>() {}) when (result) { is Response.OK -> assertEquals(result.content, "Hello") is Response.Error -> fail() } }
方案3:关闭Jackson严格子类型检查(不推荐)
临时关闭FAIL_ON_INVALID_SUBTYPE配置绕过类型检查,但可能隐藏其他类型问题:
val objectMapper = ObjectMapper().registerModule(KotlinModule()) objectMapper.configure(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE, false)
测试验证
修改后重新运行测试代码,即可正常解析OK和ERROR两种类型的JSON响应。
内容的提问来源于stack exchange,提问作者Jan
相关产品推荐
相关产品推荐

