如何将JSON反序列化为与Kotlin + Jackson的List <SomeType>

什么是反序列化以下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) 

上面的语法是不正确的,并给出: only classes are allowed on the left hand side of a class literal

注: 从@ IRUS的答案也是正确的,它正在修改,同时我写这个来填补更多的细节。

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

你的第一个代码示例:

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

因为您没有指定更多的类型信息,所以返回一个List<*>的推断类型,它实际上是一个List<Map<String,Any>> ,它不是真的“工作正常”,但不会产生任何错误。 这是不安全的,没有输入。

第二个代码应该是:

 import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.fasterxml.jackson.module.kotlin.readValue val mapper = jacksonObjectMapper() // ... val genres: List<GenreDTO> = mapper.readValue(json) 

在任务的右侧,您不需要任何其他的东西,Jackson的Kotlin模块将会对泛型进行具体化,并在内部为Jackson创建TypeReference 。 注意readValue导入,你需要这个或者.* com.fasterxml.jackson.module.kotlin包来使扩展函数完成所有的魔术。

稍微不同的另一种方法也是可行的:

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

没有理由不使用Jackson的扩展函数和附加模块。 它很小,并解决了其他问题,需要你跳过箍来做一个默认的构造函数,或使用一堆注释。 通过这个模块,你的类可以是正常的Kotlin(可选是data类):

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

以下代码适合我:

 import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.module.kotlin.readValue import com.fasterxml.jackson.module.kotlin.registerKotlinModule val json = """[ { "id" : "1", "name" : "Blues" }, { "id" : "0", "name" : "Rock" } ]""" data class GenreDTO(val id: Int, val name: String) val mapper = ObjectMapper().registerKotlinModule() fun main(args: Array<String>) { val obj: List<GenreDTO> = mapper.readValue(json) obj.forEach { println(it) } } 

这个工作是因为jackson-kotlin-module(使用了物化的泛型)里面定义的扩展函数:

  public inline fun <reified T: Any> ObjectMapper.readValue(content: String): T = readValue(content, object: TypeReference<T>() {}) 

谢谢@JaysonMinard通知我。

输出:

 GenreDTO(id=1, name=Blues) GenreDTO(id=0, name=Rock) 

你得到的错误是关于下面的表达式:

 List<GenreDTO>::class.java 

由于jvm如何对待泛型, List<GenreDTO>没有单独的类,因此编译器会抱怨。 同样在Java中,下面的代码不会被编译:

 List<GenreDTO>.getClass() 

以下是一个将正确反序列化列表的示例:

 val value:List<GenreDTO> = mapper.readValue(json, object : TypeReference<List<GenreDTO>>() {}) 

正如@JaysonMinard指出的,你可以使用jackson-module-kotlin来简化调用:

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

这是可能的,因为reified type parameters 。 考虑看Extensions找出细节。