【问题标题】:Kotlin reading json unknown type SpringKotlin 读取 json 未知类型 Spring
【发布时间】:2021-11-11 13:45:18
【问题描述】:

我正在调用不同的 API,它们在 JSON 文件中使用相同的键名。根据响应,有一个字段可能是不同的类型。

要明确:

  • 调用 API nº1 时的关键“结果”是 JSON 对象

  • 调用 API nº2 时的关键“结果”是 JSON 数组

使用第二个 API 时,我的代码如下所示:

data class Result(
    @SerializedName("results") var persons:ArrayList<Person> =ArrayList()
)

问题是是否有任何方法可以使用同一个类,而无需注意它是 JSON 数组还是 JSON 对象。

【问题讨论】:

  • 我会说你最好的选择是创建一个自定义反序列化器。

标签: json spring kotlin


【解决方案1】:

我相信您可以将结果定义为com.fasterxml.jackson.databind.JsonNode的实例。

data class Result(
    val results: JsonNode
)    

然后您可以根据 results 的类型来处理它 - 无论是 ArrayNode 还是 ObjectNode(两者都扩展 JsonNode):

fun processResults(results: JsonNode) = when{
  results.isArray -> processArrayNode(results)
  else -> processObjectNode(results)
}

private fun processArrayNode(list: JsonNode): *return whatever you need*{
  val elements = list
             .elements()
             .asSequence()
             .toList()

  val mappedElements = elements.map{
    processObjectNode(it)
  }

// do whatever you need with the array
}

private fun processObjectNode(person: JsonNode): *return whatever you need*{
  //** this will transform the json node into a linkedHashMap where the keys are the json keys and the values are the values (here interpreted as jsonNodes) **/
  val fieldsMap = person
                .fields()
                .asSequence()
                .associateBy( {it.key}, {it.value} )
  
  // process whatever you need
}

这是对两个 API 调用使用相同 DTO 的一种方法。在我看来,额外的工作是不值得的。我将创建两个包含results 字段的DTO,其中一个是Person 的实例,另一个是List&lt;Person&gt; 的实例。

编辑:对上述 sn-p 的一个小升级是向 JsonNode 添加扩展方法:

fun JsonNode.elementsToList(): List<JsonNode> = this
    .elements()
    .asSequence()
    .toList()

fun JsonNode.fieldsToMap(): Map<String, JsonNode> = this
    .fields()
    .asSequence()
    .associateBy({it.key}, {it.value})

【讨论】:

    【解决方案2】:

    您可以使用ObjectMapper.typeFactory.constructParametricType 来处理泛型类型:

    data class Result<T>(
      var x:T
    )
    
    val om = ObjectMapper()
    om.registerModule(KotlinModule())
    val parsedList = om.readValue<Result<List<String>>>(
      """{"x":["x1", "x2"]}""", 
      om.typeFactory.constructParametricType(Result::class.java, List::class.java)
    )
    println(parsedList)
    val parsedMap = om.readValue<Result<Map<String, String>>>(
      """{"x":{"k1": "v1", "k2": "v2"}}""", 
      om.typeFactory.constructParametricType(Result::class.java, Map::class.java)
    )
    println(parsedMap)
    

    给出输出:

    Result(x=[x1, x2])
    Result(x={k1=v1, k2=v2})
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-01-20
      • 1970-01-01
      • 2019-03-22
      • 1970-01-01
      • 2020-10-21
      • 2018-07-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多