杰克逊:用不同的模型解析相同的密钥

Jackson: Parse same key with different model

在 Kotlin 中,我使用 jackson (fasterxml) 来解析端点响应 (JSON)。它看起来类似于:

{
...
steps: [
   {
      "status":200,
      "id":"A",
      "data":{
         "score":"10"
      }
   },
   {
      "status":200,
      "id":"B",
      "data": {
         "dateOfBirth":"10-09-1994",
         "fullname": "Peter",
         ...
      }
   },
   {
      "status":200,
      "id":"C",
      "data": {
         "dateOfBirth": {
             "value": "10-03-1993"
          },
         ...
      }
   },
]
...
}

我的代码如下所示:


...
response.readEntity(DocumentResponse::class.java)
...



@JsonIgnoreProperties(ignoreUnknown = true)
data class DocumentResponse @JsonCreator constructor(
    @JsonProperty("steps")
    val steps: List<StepResponse>
) 

data class StepResponse @JsonCreator constructor(
    @JsonProperty("status")
    val status: String,
    @JsonProperty("id")
    val id: String,
    @JsonProperty("data")
    val data: Data?
)

@JsonIgnoreProperties(ignoreUnknown = true)
class Data @JsonCreator constructor(
    @JsonProperty("dateOfBirth")
    val dateOfBirth: String?,
    @JsonProperty("fullName")
    val fullName: String?,
    @JsonProperty("dni")
    val dni: String?,
    ...
) 

问题是data可以有多种类型,我想从JSON中获取这个字段只有当id是“B”时 .当检索并读取 JSON 时,会抛出一个错误,因为它读取了 ID 为“A”的步骤,但未找到 dateOfBirth,因此会抛出以下错误:

MistmatchedInputException:无法从 START_OBJECT 令牌中反序列化字符串实例 ...

如果 data 字段与 JSON 格式不匹配,是否可以忽略该字段? 我想阅读 JSON,但唯一与我相关的 data 是与特定 ID 相关的内容!

我会说你最好的选择是为 StepResponse:

使用自定义解串器
import com.fasterxml.jackson.databind.deser.std.StdDeserializer
import com.fasterxml.jackson.core.JsonParser
import com.fasterxml.jackson.databind.DeserializationContext
import com.fasterxml.jackson.databind.JsonNode

class StepResponseDeserializer constructor(vc: Class<*>? = null) : StdDeserializer<StepResponse>(vc) {
    override fun deserialize(jp: JsonParser, ctxt: DeserializationContext): StepResponse {
        val node = jp.codec.readTree<JsonNode>(jp)
        val status = node["status"].asText()
        val id = node["id"].asText()

        val data = if ("B" == id) {
            val dataNode = node["data"]
            val dateOfBirth = dataNode["status"].asText()
            val fullName = dataNode["fullName"].asText()
            val dni = dataNode["dni"].asText()
            Data(dateOfBirth, fullName, dni)
        } else null

        return StepResponse(status, id, data)
    }
}

您可以直接在class上注册解串器,如下所示:

@JsonDeserialize(using = StepResponseDeserializer.class)
data class StepResponse @JsonCreator constructor(
    val status: String,
    val id: String,
    val data: Data?
)

作为旁注,您可以删除所有 @JsonProperty 注释,因为只有在 Java/Kotlin 属性 名称与 JSON 属性 名字.