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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/33368328/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 18:07:17  来源:igfitidea点击:

How to use Hymanson to deserialize to Kotlin collections

jsonHymansonkotlin

提问by Marvin

Sample code what I want:

我想要的示例代码:

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> = HymansonObjectMapper().whatMethodAndParameter?

回答by Jayson Minard

With Hymanson Kotlin Module current versions, if you import the full module package or the specific extension function you'll have all extension methods available. Such as:

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

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

Therefore the Hymanson Module for Kotlin will infer the the correct type and you do not need a TypeReferenceinstance.

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

so your case (slightly renamed and fixed the data class, and JSON):

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

import com.fasterxml.Hymanson.module.kotlin.readValue

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

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

You can also use the form:

您还可以使用以下表格:

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

Without the import you will have an error because the extension function is not found.

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

回答by desseim

TL;DR

TL; 博士

With Hymanson 2.6.3-2do as @jason-minard advises and simply use:

Hyman逊2.6.3-2按照@jason-minard 的建议做,只需使用:

import com.fasterxml.Hymanson.module.kotlin.readValue

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

Details

细节

There's nothing special about Kotlin wrt to deserializing collections, although you'll need the kotlin Hymanson moduleto deserialize data classes without annotations.

Kotlin 在反序列化集合方面没有什么特别之处,尽管您需要kotlin Hymanson 模块来反序列化没有注释的数据类。

Namely, it will require full reified type information in your case in order to keep track of the generic parameter of the list (D) ; otherwise (e.g. if you use readValue(jsonStr, List::class.java)) Hymanson will only see it as an erased type (i.e. List) (as Kotlin makes explicit) and deserialize it to a List<Map<String, String>>, not knowing it has to construct Ds. This is worked aroundby using an anonymous subclass of TypeReferencein Java so that Hymanson can access the full reified type to deserialize to at run time.

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

Translating Hymanson Java code literally to Kotlin, the following thus achieves what you want (and as commented by @eski, notice that the JSON in your example is invalid):

将 Hymanson Java 代码从字面上翻译为 Kotlin,因此以下实现了您想要的(并且正如@eski 所评论的,请注意您示例中的 JSON 无效):

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

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

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

This is a bit verbose and ugly though, so you could hide it in a Kotlin (extension) function (especially if you plan on using it several times):

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

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

which would allow you to then just call:

这将允许您然后调用:

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

And this is just what's included in the 2.6.3-2Hymanson Kotlin module.

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

回答by fabriciorissetto

If you don't have the type of your generic content, like <MyData>in the example below:

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

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

You can make it by implementing not only the JsonSerialzierbut also the ContextualDeserializerlike in the code sample below (based on this answerin Java):

您可以通过在下面的代码示例中不仅实现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)
    }
}