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

时间:2015-10-27 12:44:10

标签: json jackson kotlin

我想要的示例代码:

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?

3 个答案:

答案 0 :(得分:26)

使用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 Module将推断出正确的类型,而您不需要TypeReference实例。

所以你的情况(稍微重命名并修复了数据类和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)

如果没有导入,您将收到错误,因为找不到扩展功能。

答案 1 :(得分:12)

TL; DR

杰克逊2.6.3-2做@ jason-minard建议并简单地使用:

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

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

详细

对于deserializing collections来说Kotlin wrt并没有什么特别之处,尽管你需要kotlin jackson module来反序列化没有注释的数据类。

即,在您的情况下,它将需要完整的具体类型信息,以便跟踪列表的通用参数(D);否则(例如,如果你使用readValue(jsonStr, List::class.java))杰克逊只会将其视为已擦除类型(即List)(如Kotlin所示)并将其反序列化为List<Map<String, String>>,但不知道它有构建D s。这是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杰克逊Kotlin模块中包含的内容。

答案 2 :(得分:0)

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

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

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

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)
    }
}