如何使用 jackson 反序列化为 Kotlin 集合

How to use jackson to deserialize to Kotlin collections

我想要的示例代码:

data class D(val a: String, val b: Int)
val jsonStr = """[{"a": "value1", "b": 1}, {"a": "value2", "b":"2}]"""
// what I need
val listOfD: List<D> = jacksonObjectMapper().whatMethodAndParameter?

TL;DR

Jackson 2.6.3-2 按照@jason-minard 的建议做,简单地使用:

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

val listOfD: List<D> = jacksonMapper.readValue(jsonStr)

详情

Kotlin 没有什么特别之处 deserializing collections, although you'll need the kotlin jackson module 反序列化数据 类 没有注释。

也就是说,在您的情况下,它需要完整的具体化类型信息,以便跟踪列表的通用参数 (D);否则(例如,如果您使用 readValue(jsonStr, List::class.java))Jackson 只会将其视为已擦除类型(即 List)(正如 Kotlin 明确指出的那样)并将其反序列化为 List<Map<String, String>>,而不知道它具有构造 Ds。这是 worked around 通过在 Java 中使用 TypeReference 的匿名子类,以便 Jackson 可以在 运行 时间访问完整的具体化类型以反序列化。

将 Jackson Java 代码从字面上翻译成 Kotlin,以下实现了您想要的(正如@eski 评论的那样,请注意示例中的 JSON 是无效的):

val jacksonMapper = ObjectMapper().registerModule(KotlinModule())

val jsonStr = """[{"a": "value1", "b": 1}, {"a": "value2", "b":2}]"""
val listOfD: List<D> = jacksonMapper.readValue(jsonStr, object : TypeReference<List<D>>(){})

assertEquals(listOf(D("value1", 1), D("value2", 2)), listOfD)

虽然这有点冗长和丑陋,因此您可以将它隐藏在 Kotlin(扩展)函数中(特别是如果您计划多次使用它):

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

这样您就可以调用:

val listOfD: List<D> = jacksonMapper.readValue(jsonStr)

这正是 2.6.3-2 jackson Kotlin 模块中包含的内容。

使用 Jackson Kotlin 模块 current versions,如果您导入完整的模块包或特定的扩展函数,您将拥有所有可用的扩展方法。如:

import com.fasterxml.jackson.module.kotlin.*  
val JSON = jacksonObjectMapper()  // keep around and re-use
val myList: List<String> = JSON.readValue("""["a","b","c"]""")

因此,Kotlin 的 Jackson 模块将推断出正确的类型,您不需要 TypeReference 实例。

所以你的情况(稍微重命名并修复了数据 class 和 JSON):

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

data class MyData(val a: String, val b: Int)
val JSON = jacksonObjectMapper()  

val jsonStr = """[{"a": "value1", "b": 1}, {"a": "value2", "b": 2}]"""
val myList: List<MyData> = JSON.readValue(jsonStr)

您还可以使用以下形式:

val myList = JSON.readValue<List<MyData>>(jsonStr)

如果没有导入,您将遇到错误,因为找不到扩展函数。

如果您没有通用内容的类型,例如下面示例中的 <MyData>

val value = context.readValue<List<MyData>>(parser, valueType)

您不仅可以实现 JsonSerialzier,还可以实现下面代码示例中的 ContextualDeserializer(基于 Java 中的 ):

class GenericListDeserializer : JsonDeserializer<List<*>>(), ContextualDeserializer {
    private var valueType: JavaType? = null

    override fun createContextual(ctxt: DeserializationContext, property: BeanProperty): JsonDeserializer<List<*>> {
        val wrapperType = property.type
        val valueType = wrapperType.containedType(0)
        val deserializer = GenericListDeserializer()
        deserializer.valueType = valueType
        return deserializer
    }

    override fun deserialize(parser: JsonParser, context: DeserializationContext): List<*> {
        val value :Any? = context.readValue(parser, valueType)
        return listOf(value)
    }
}