Jackson Kotlin - 反序列化 JsonNode

2024-05-23

Problem

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

我尝试过的

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

图书馆

  • 杰克逊核心:2.9.9
  • 杰克逊模块 kotlin:2.9.9
  • 科特林 1.3.41
  • kotlin-stdlib-jdk8:1.3.41

Code

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 内联扩展函数(这意味着泛型在运行时被保留),它调用 JavaObjectMapper.treeToValue(TreeNode, Class<T>)方法。传递的值作为Class<T>将丢失泛型类型的泛型类型信息,例如List<Comment>,因为类型擦除。

So 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 - 在地图中反序列化

Because 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
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Jackson Kotlin - 反序列化 JsonNode 的相关文章

随机推荐

  • Delphi - 如何使用 iPhone 作为图片源通过 OpenDialog 获取目录

    我有一个 Delphi 应用程序 D2010 它允许用户通过 OpenDialog 选择 JPG 文件 当我从普通 Windows 目录中选择文件时 我的 TOpenDialog Filename 包含该文件的完整路径 并且我的代码可以正常
  • npm install 的问题(Angular)

    今天我尝试创建一个新项目 所以我使用这个命令 ng new NAME style less 并在我的cmder中弹出错误和警告 所以我卸载了 Roaming npm 和 npm cache 中的节点和文件 然后我安装了node并再次下载cm
  • 使用受邀用户列表发起视频群聊

    我有一个网站 一些拥有有效 Gmail ID 的人正在进行讨论 如果讨论中的其中一个人点击了 google Hangout 按钮 我需要使用已经邀请的讨论中的用户列表开始一个 Hangout 即我需要避免添加参与者打开环聊应用程序时出现的弹
  • iPad Safari Web Inspector 在页面加载时崩溃

    我有一个用 WordPress 制作的以视频为中心的网站 当我们在 iPad 上测试网站时 我们将其连接到 Mac 笔记本电脑并打开 safari 开发人员工具来检查是否有任何错误等 我们的主页上一切正常 但当我们转到我们添加的任何视频帖子
  • “create_date”时间戳字段的默认值无效

    我有以下 sql 创建语句 mysql gt CREATE TABLE IF NOT EXISTS erp je menus gt id INT 11 NOT NULL AUTO INCREMENT gt name VARCHAR 100
  • Android-如何将 android.net.Uri 对象转换为 java.net.URI 对象?

    我正在尝试获得一个FileInputStream用户从图片库中选择的图像上的对象 这是安卓URI由返回android provider MediaStore Images Media INTERNAL CONTENT URI content
  • 使用 EclipseLink Modelgen 处理器和 Spring Security 时如何解决 CompletionFailure?

    我正在尝试在一个项目中使用 Spring Security 其中我使用 eclipselink 作为 modelgen 处理器来生成静态元模型 当我尝试这样做时 我遇到奇怪的编译错误 例如 gt java lang RuntimeExcep
  • VBA复制单元格值和格式

    我如何修改以下代码以便不仅复制值而且复制字体样式 例如大胆或不大胆 谢谢 Private Sub CommandButton1 Click Dim i As Integer Dim a As Integer a 15 For i 11 To
  • 当系统上没有留下任何可执行文件时,如何卸载 Windows 服务?

    当系统上没有留下任何可执行文件时 如何卸载 Windows 服务 我跑不了installutil u因为系统上没有留下可执行文件 我仍然可以在服务控制台中看到该服务的条目 出现这种状态的原因可能是因为 msi 包中存在问题 没有正确删除服务
  • 如何为 HOC 创建共享状态?

    我创造了LoadBookHOC包裹着BookDetails and BookSummary成分 LoadBookHOC js const LoadBookHOC InnerComponent gt class LoadBook extend
  • 点击继续并登录以检查下载。 [沙盒]

    有时我会收到一个非常烦人的对话框 其中包含以下文字 点击继续并登录以检查下载 如果我登录 使用沙箱用户 或点击取消 对话框将立即再次显示 我正在使用非续订订阅和非消耗产品 有什么想法如何摆脱这个对话框吗 Thanks Martin 共识似乎
  • Swift 1.2 可选外部变量?

    由于 Swift 无法访问编译变量 因此我创建了一个指向编译变量的 Objective C extern 变量 编译变量转换器 h extern NSString const NetworkApiBasicAuthUsername 编译变量
  • Tinymce 添加自定义样式的快捷方式

    在我的tinymce初始化中我使用我的预定义样式 style formats title Date inline span classes date title Trend UP inline span classes trend up t
  • 名称节点处于安全模式

    我提到了这些问题名称节点处于安全模式 无法离开 https stackoverflow com questions 15803266 name node is in safe mode not able to leave and SafeM
  • 如何在 Ubuntu 10.04 上安装适用于 python 3 的 pycairo

    我正在尝试安装 pycairo 1 10 0 以便与我的自定义构建 python 3 1 一起使用 然而 sudo flower bin easy install 3 1 pycairo 失败了 XXX XXXX adventures su
  • 在返回响应之前获取 servlet 请求的状态

    晚上好 我正在编写一个 Java Servlet Struts 2 Tomcat JSP 等 它能够进行一些相当复杂的模拟 这些可能最多需要 2 分钟才能完成 并将返回结果图表 计算模拟完成的百分比很简单 因为该过程是通过重复相同的计算数千
  • Discord 使用机器人创建频道

    我正在制作一个不和谐的机器人 并且我正在尝试利用所示的 createChannel 函数here http discordjs readthedocs io en latest docs client html createchannel
  • 在 subversion 中看到许多提交的组合差异?

    我被要求审查 SVN 版本号 123 178 199 245 和 288 中所做的更改 这些都是与特定功能相关的提交 解决这个问题的合理方法是什么 我想我真的想以某种方式查看收集的差异 但我愿意接受建议 我们现在正在修订 400 编辑 我想
  • Laravel 5.4 将json保存到数据库

    帮我将 json 保存到数据库 表字段类型 文本 我有带有强制转换数组的模型 class Salesteam extends Model protected casts team members gt array 我想要像这样 index
  • Jackson Kotlin - 反序列化 JsonNode

    Problem 我有字符串形式的 JSON 内容 我首先想用 Jackson 以编程方式遍历它 然后 当我有感兴趣的节点时 我想反序列化它 我尝试过的 我已使用 mapper readValue 成功反序列化字符串 但现在我想在 jsonN