gpt4 book ai didi

json - Jackson Kotlin - 反序列化 JsonNode

转载 作者:行者123 更新时间:2023-12-02 12:41:29 32 4
gpt4 key购买 nike

问题

我有字符串形式的 JSON 内容,我首先想用 Jackson 以编程方式遍历它。然后,当我有感兴趣的节点时,我想反序列化它。

我尝试过的

我已经使用 mapper.readValue 成功反序列化了字符串,但现在我想在 jsonNode 而不是字符串上执行这样的操作。

图书馆

  • jackson 核心:2.9.9
  • jackson-module-kotlin:2.9.9
  • Kotlin 1.3.41
  • kotlin-stdlib-jdk8:1.3.41

代码

package somepackage

import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.KotlinModule
import com.fasterxml.jackson.module.kotlin.readValue
import com.fasterxml.jackson.module.kotlin.treeToValue

fun main() {
val mapper = ObjectMapper().registerModule(KotlinModule())

readValueWorksFine(mapper)
treeToValueFails(mapper)
}

fun treeToValueFails(mapper: ObjectMapper) {
val fullJsonContent = """
[{
"product_id":123,
"Comments":
[{
"comment_id": 23,
"message": "Hello World!"
}]
}]
""".trimIndent()

// Traverse to get the node of interest
val commentsNode: JsonNode = mapper.readTree(fullJsonContent).get(0).get("Comments")

// Deserialize
val comments: List<Comment> = mapper.treeToValue<List<Comment>>(commentsNode)

// The line below fails. (I would have expected the exception to be thrown in the line above instead.
// Exception:
// Exception in thread "main" java.lang.ClassCastException: class
// java.util.LinkedHashMap cannot be cast to class somepackage.Comment (java.util.LinkedHashMap is in module
// java.base of loader 'bootstrap'; somepackage.Comment is in unnamed module of loader 'app')
for (comment: Comment in comments) { // This line fails
println(comment.comment_id)
println(comment.message)
}
}

fun readValueWorksFine(mapper: ObjectMapper) {
val commentsJsonContent = """
[{
"comment_id": 23,
"message": "Hello World!"
}]
""".trimIndent()

val comments1: List<Comment> = mapper.readValue<List<Comment>>(commentsJsonContent)
for (comment in comments1) {
println(comment)
}
}

data class Comment(val comment_id: Long, val message: String)

异常/输出

上面的代码导致以下异常/输出:

Comment(comment_id=23, message=Hello World!)
Exception in thread "main" java.lang.ClassCastException: class java.util.LinkedHashMap cannot be cast to class somepackage.Comment (java.util.LinkedHashMap is in module java.base of loader 'bootstrap'; somepackage.Comment is in unnamed module of loader 'app')
at somepackage.TKt.treeToValueFails(T.kt:39)
at somepackage.TKt.main(T.kt:13)
at somepackage.TKt.main(T.kt)

最佳答案

问题原因

尽管ObjectMapper.treeToValue是具有具体化泛型参数的 Kotlin 内联扩展函数(这意味着泛型在运行时保留),它调用 Java ObjectMapper.treeToValue(TreeNode, Class<T>)方法。值传递为 Class<T>将丢失通用类型的通用类型信息,例如 List<Comment> , 因为类型删除。

所以 treeToValue可用于:

mapper.treeToValue<Comment>(commentNode)

但不适用于:

mapper.treeToValue<List<Comment>>(commentsNode)

另请注意 ObjectMapper包含多个具有 @SuppressWarnings 的方法注解,导致一些问题不会出现在编译时,而是出现在运行时。

解决方案 1 - 使用 convertValue()

这是最好的解决方案。它使用 Kotlin 扩展函数 ObjectMapper.convertValue .

val commentsNode = mapper.readTree(fullJsonContent).get(0).get("Comments")
val comments = mapper.convertValue<List<Comment>>(commentsNode)

解决方案 2 - 使用 ObjectReader

此解决方案不使用 jackson-module-kotlin扩展功能。

val reader = mapper.readerFor(object : TypeReference<List<Comment>>() {})
val comments: List<Comment> = reader.readValue(commentsNode)

解决方案 3 - 在 map 中反序列化

因为 treeToValue (Kotlin 扩展函数)确实适用于非泛型类型,您可以首先获取节点作为 JsonNode 列表,然后将每个 JsonNode 映射到 Comment。

但是你不能简单地返回 mapper.treeToValue(it) 很麻烦,因为这会导致类型推断编译错误。

val commentsNode = mapper.readTree(fullJsonContent).get(0).get("Comments")
val comments = commentsNode.elements().asSequence().toList().map {
val comment: Comment = mapper.treeToValue(it)
comment
}

关于json - Jackson Kotlin - 反序列化 JsonNode,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57279171/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com