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

Jas*_*ues 18 json jackson kotlin

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

[ {
  "id" : "1",
  "name" : "Blues"
}, {
  "id" : "0",
  "name" : "Rock"
} ]
Run Code Online (Sandbox Code Playgroud)

我试过了:

//Works OK
val dtos  = mapper.readValue(json, List::class.java)
Run Code Online (Sandbox Code Playgroud)

不过我想:

val dtos : List<GenreDTO>  = mapper.readValue(json, 
    List<GenreDTO>::class.java)
Run Code Online (Sandbox Code Playgroud)

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

Jay*_*ard 28

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

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

您的第一个代码示例:

val dtos  = mapper.readValue(json, List::class.java)
Run Code Online (Sandbox Code Playgroud)

返回一个推断类型,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)
Run Code Online (Sandbox Code Playgroud)

你不需要在任务的右侧做任何其他事情,杰克逊的Kotlin模块将重新设计仿制品并在TypeReference内部创建杰克逊.注意readValue导入,您需要或.*com.fasterxml.jackson.module.kotlin包的扩展功能是做所有的魔力.

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

val genres = mapper.readValue<List<GenreDTO>>(json)
Run Code Online (Sandbox Code Playgroud)

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

class GenreDTO(val id: Int, val name: String)
Run Code Online (Sandbox Code Playgroud)

  • 我正在为 Jackson 使用 Kotlin 模块,并尝试过类似的操作,但忘记了导入。 (2认同)
  • 我希望 https://youtrack.jetbrains.com/issue/KT-9238 能够让库告诉 IDE 哪些导入对其很重要。 (2认同)

mie*_*sol 7

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

List<GenreDTO>::class.java
Run Code Online (Sandbox Code Playgroud)

由于jvm如何处理泛型,List<GenreDTO>因此编译器抱怨没有单独的类.同样在Java中,以下内容不会编译:

List<GenreDTO>.getClass()
Run Code Online (Sandbox Code Playgroud)

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

val value:List<GenreDTO> = mapper.readValue(json, object : TypeReference<List<GenreDTO>>() {})
Run Code Online (Sandbox Code Playgroud)

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

val genres: List<GenreDTO> = mapper.readValue(json)
// or
val genres = mapper.readValue<List<GenreDTO>>(json)
Run Code Online (Sandbox Code Playgroud)

这是可能的,因为reified type parameters.考虑查看Extensions详细信息.


Rus*_*lan 5

以下代码适合我:

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)
    }
}
Run Code Online (Sandbox Code Playgroud)

因为杰克逊-科特林模块(即使用内定义的扩展功能的这一工作物化泛型):

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

谢谢@JaysonMinard通知我.

输出:

GenreDTO(id=1, name=Blues)
GenreDTO(id=0, name=Rock)
Run Code Online (Sandbox Code Playgroud)