【问题标题】:parse generic sealed class in kotlin using jackson使用杰克逊解析科特林中的通用密封类
【发布时间】:2022-12-19 16:06:36
【问题描述】:

我有以下代表网络响应状态的通用密封类。

@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": "OK" 在这种情况下它包含一个 content 键(具有通用值)_ 或 "status": "ERROR" 在这种情况下它包含一个 error 键(具有通用值)

例如:

{
  "status": "OK",
  "content": "Hello"
}

或者

{
  "status": "ERROR",
  "error": "MyError"
}

我的解析失败但有消息

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]
@Nested
inner class ContentParsingTests {
    @Test
    fun `parses OK response`() {
        val json = """
    {
      "status": "OK",
      "content": "Hello"
    }
    """.trimIndent()

        when (val result = objectMapper.readValue<Response<String, String>>(json)) {
            is Response.OK -> {
                assertEquals(result.content, "Hello")
            }
            is Response.Error -> {
                fail()
            }
        }
    }

    @Test
    fun `parses ERROR response`() {
        val json = """
        {
          "status": "ERROR",
          "error": "MyError"
        }
    """.trimIndent()

        when (val result = objectMapper.readValue<Response<String, String>>(json)) {
            is Response.OK -> {
                fail()
            }
            is Response.Error -> {
                assertEquals(result.error, "MyError")
            }
        }
    }
}

我注意到只要内容是通用的,解析就可以正常工作:

sealed class Response<out Content > {
    data class OK<out Content>(val content: Content) : Response<Content>()
    object Error : Response<Nothing>()
}

但当然我丢失了错误负载

将 json 解析为我的泛型类的正确方法是什么?

【问题讨论】:

    标签: json kotlin jackson


    【解决方案1】:

    对于这种情况,您根本不需要泛型。只需:

    @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 interface Response {
      data class Success(val content: Content): Response
      data class Error(val error: Error): Response
    }
    

    Jackson 将能够正确解析所有内容。

    【讨论】:

      猜你喜欢
      • 2014-08-22
      • 1970-01-01
      • 2020-10-16
      • 2019-11-25
      • 2021-09-17
      • 2014-06-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多