如何将JSON反序列化为List< SomeType>与科特林+杰克逊

问题描述:

反序列化以下JSON的正确语法是什么:

What is the correct syntax to deserialize the following JSON:

[ {
  "id" : "1",
  "name" : "Blues"
}, {
  "id" : "0",
  "name" : "Rock"
} ]

我试过:

//Works OK
val dtos  = mapper.readValue(json, List::class.java)

但是我想要:

val dtos : List<GenreDTO>  = mapper.readValue(json, 
    List<GenreDTO>::class.java)

上面的语法不正确,并给出:只允许在类文字的左侧使用类

The above syntax is not correct and gives: only classes are allowed on the left hand side of a class literal

注意: @IRus的答案也是正确的,它是在我写这篇文章的同时被修改的填写更多详细信息。

您应该使用 Jackson + Kotlin模块或者当你没有默认构造函数时,你会有其他问题反序列化为Kotlin对象。

You should use the Jackson + Kotlin module or you will have other problems deserializing into Kotlin objects when you do no have a default constructor.

你的第一个代码示例:

val dtos  = mapper.readValue(json, List::class.java)

由于您未指定更多类型信息,因此返回列表< *> 的推断类型,它实际上是列表< Map< String,Any>&gt ; 这不是真的正常,但没有产生任何错误。这是不安全的,不是打字的。

Is returning an inferred type of List<*> since you did not specify more type information, and it is actually a List<Map<String,Any>> which is not really "working OK" but is not producing any errors. It is unsafe, not typed.

第二个代码应该是:

import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.fasterxml.jackson.module.kotlin.readValue

val mapper = jacksonObjectMapper()
// ...
val genres: List<GenreDTO> = mapper.readValue(json)

在作业的右侧,您不需要任何其他内容,杰克逊的Kotlin模块将重新统一泛型,并在内部为杰克逊创建 TypeReference 。注意 readValue 导入,你需要。* 来获取 com.fasterxml.jackson .module.kotlin 包具有完成所有魔法的扩展功能。

You do not need anything else on the right side of the assignment, the Kotlin module for Jackson will reify the generics and create the TypeReference for Jackson internally. Notice the readValue import, you need that or .* for the com.fasterxml.jackson.module.kotlin package to have the extension functions that do all of the magic.

一个稍微不同的替代方案也有效:

A slightly different alternative that also works:

val genres = mapper.readValue<List<GenreDTO>>(json)

没有理由不使用Jackson的扩展功能和附加模块。它很小并且解决了其他需要你跳过箍来制作默认构造函数或者使用一堆注释的问题。使用该模块,您的类可以是普通的Kotlin(可选为数据类):

There is no reason to NOT use the extension functions and the add-on module for Jackson. It is small and solves other issues that would require you to jump through hoops to make a default constructor, or use a bunch of annotations. With the module, your class can be normal Kotlin (optional to be data class):

class GenreDTO(val id: Int, val name: String)