如何将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
找出细节。