我有以下表示网络响应状态的泛型密封类.

@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密钥.

对于我正在与之交谈的每个端点,contenterror键下的类型可以不同.因此需要泛型类型

例如,一个endpoit返回String作为类型,所以Response<String, String>

{
  "status": "OK",
  "content": "Hello"
}
{
  "status": "ERROR",
  "error": "MyError"
}

另一个endpoit返回Double作为内容,Int作为错误,因此

Response<Double, Int>

{
  "status": "OK",
  "content": 2.0
}
{
  "status": "ERROR",
  "error": 1
}

我的解析失败,但出现消息

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解析成我的泛型类的正确方法是什么?

推荐答案

我认为问题出在Nothing,因为它就像Void,你不能创建它的实例,也不能获得类型信息,这就是为什么序列化库要为它苦苦挣扎的原因.因此,当前问题的一个解决方案是像这样更新模型定义,并且它是有效的.不过,这并不理想.

sealed class Response<out Content, out Error> {

    data class OK<out Content, out Error>(val content: Content) : Response<Content, Error>()

    data class Error<out Content, out Error>(val error: Error) : Response<Content, Error>()
}

Json相关问答推荐

如何编写MongoDB查询以返回数组数组

Jolt变换将字段移动到数组的每个元素中

在Reaction中从JSON文件中筛选数组

Pandas 对REST API的自定义响应

jq如何合并两个json对象

使用 jq 获取所有嵌套键和值

使用不同行数的数据创建嵌套Jolt

jq :遍历 json 并在键存在时检索集合

JSON 的自定义编组器,可以是字符串或 map[string]string / map[string]bool

修改 boost::json::object 中的值

JOLT 获取带有动态键的数组

Servicestack 返回数组而不是带有数组的对象

C# 合并 2 个几乎相同的 JSON 对象

如何使用 CORS 实现 JavaScript Google Places API 请求

将带有数据和文件的 JSON 发布到 Web Api - jQuery / MVC

如何使用 Jackson 重命名 JSON 序列化中的根键

将 Objective-C 对象序列化和反序列化为 JSON

在 Android 中使用带有 post 参数的 HttpClient 和 HttpPost

使用适用于 Python 的 Google API - 我从哪里获取 client_secrets.json 文件?

Java HashMap 与 JSONObject