如何使用 Kotlin + Jackson 将 JSON 反序列化为 List<SomeType>
How do I deserialize JSON into a List<SomeType> with Kotlin + Jackson
反序列化以下 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
以下代码对我来说效果很好:
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 中定义的扩展函数(使用 reified 泛型):
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>
没有单独的 class,因此编译器会抱怨。类似地,在 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
. Consider looking at Extensions
要了解详情。
NOTE: @IRus 的回答也是对的,和我同时修改写这个是为了填写更多的细节。
您应该使用 Jackson + Kotlin module,否则当您没有默认构造函数时,在反序列化为 Kotlin 对象时会遇到其他问题。
您的第一个代码示例:
val dtos = mapper.readValue(json, List::class.java)
正在返回推断类型 List<*>
因为您没有指定更多类型信息,它实际上是一个 List<Map<String,Any>>
而不是 "working OK" 但不会产生任何错误.不安全,不打字
第二个代码应该是:
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 使用扩展功能和 add-on 模块。它很小并且解决了其他问题,这些问题需要您跳过箍来制作默认构造函数或使用一堆注释。使用该模块,您的 class 可以是普通的 Kotlin(可选 data
class):
class GenreDTO(val id: Int, val name: String)
反序列化以下 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
以下代码对我来说效果很好:
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 中定义的扩展函数(使用 reified 泛型):
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>
没有单独的 class,因此编译器会抱怨。类似地,在 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
. Consider looking at Extensions
要了解详情。
NOTE: @IRus 的回答也是对的,和我同时修改写这个是为了填写更多的细节。
您应该使用 Jackson + Kotlin module,否则当您没有默认构造函数时,在反序列化为 Kotlin 对象时会遇到其他问题。
您的第一个代码示例:
val dtos = mapper.readValue(json, List::class.java)
正在返回推断类型 List<*>
因为您没有指定更多类型信息,它实际上是一个 List<Map<String,Any>>
而不是 "working OK" 但不会产生任何错误.不安全,不打字
第二个代码应该是:
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 使用扩展功能和 add-on 模块。它很小并且解决了其他问题,这些问题需要您跳过箍来制作默认构造函数或使用一堆注释。使用该模块,您的 class 可以是普通的 Kotlin(可选 data
class):
class GenreDTO(val id: Int, val name: String)