You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin使用JacksonXML反序列化Qt TS文件偶现字段报错如何解决

问题原因

你当前的崩溃源于Jackson XML反序列化的两个冲突点:

  1. Translation 类同时绑定了标签内纯文本(@JacksonXmlText)和子节点numerusform,当<translation>标签内只有纯文本没有子节点时,Jackson默认的反序列化逻辑会认为结构不匹配,抛出解析异常。
  2. 没有配置Jackson忽略未知属性/兼容非标准结构,只要遇到和定义不完全匹配的节点就会直接终止解析。

解决方案

第一步:调整数据类注解配置

给所有数据类加上忽略未知属性的注解,同时修正Translation类的冗余注解,删除不必要的自定义setter逻辑:

import com.fasterxml.jackson.annotation.JsonIgnoreProperties
import com.fasterxml.jackson.dataformat.xml.annotation.*

@JsonIgnoreProperties(ignoreUnknown = true)
data class Context(
    @JacksonXmlProperty(localName = "name")
    val name: String = "",
    @JacksonXmlElementWrapper(useWrapping = false)
    @JacksonXmlProperty(localName = "message")
    val messages: List<Message> = emptyList()
)

@JsonIgnoreProperties(ignoreUnknown = true)
data class Message(
    @JacksonXmlProperty(localName = "numerus", isAttribute = true)
    val numerus: String? = null,
    @JacksonXmlProperty(localName = "source")
    val source: String? = null,
    @JacksonXmlProperty(localName = "comment")
    val comment: String? = null,
    @JacksonXmlProperty(localName = "translation")
    val translation: Translation? = null
)

@JsonIgnoreProperties(ignoreUnknown = true)
data class Translation(
    @JacksonXmlProperty(localName = "type", isAttribute = true)
    val type: String? = null,
    @JacksonXmlText
    val text: String? = null,
    @JacksonXmlElementWrapper(useWrapping = false)
    @JacksonXmlProperty(localName = "numerusform")
    val numerusForm: List<NumerusForm> = emptyList()
)

@JsonIgnoreProperties(ignoreUnknown = true)
data class NumerusForm(
    @JacksonXmlText
    val text: String? = null
)

Jackson本身支持直接注入不可变List集合,你原来的私有中间列表+自定义setter逻辑反而容易引发注入异常。

第二步:配置XmlMapper兼容混合内容

初始化XmlMapper的时候开启兼容配置,避免结构不匹配直接崩溃:

import com.fasterxml.jackson.databind.DeserializationFeature
import com.fasterxml.jackson.dataformat.xml.XmlMapper
import com.fasterxml.jackson.dataformat.xml.deser.FromXmlParser
import com.fasterxml.jackson.module.kotlin.registerKotlinModule

val xmlMapper = XmlMapper().apply {
    // 注册Kotlin模块,支持data class的无默认构造函数反序列化
    registerKotlinModule()
    // 遇到未知属性不抛出异常,直接忽略
    configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
    // 允许将标签内的纯文本直接解析为@JacksonXmlText标注的字段
    configure(FromXmlParser.Feature.PARSE_TEXT_AS_VALUE, true)
    // 空标签解析为null而非空对象
    configure(FromXmlParser.Feature.EMPTY_ELEMENT_AS_NULL, true)
    // 允许空字符串解析为null对象
    configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true)
}

第三步(可选兜底方案):自定义Translation反序列化器

如果上面的配置还是不能兼容极端场景,可以手写自定义反序列化器手动处理两种结构:

import com.fasterxml.jackson.core.JsonParser
import com.fasterxml.jackson.databind.DeserializationContext
import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.databind.deser.std.StdDeserializer
import com.fasterxml.jackson.databind.annotation.JsonDeserialize

class TranslationDeserializer : StdDeserializer<Translation>(Translation::class.java) {
    override fun deserialize(p: JsonParser, ctxt: DeserializationContext): Translation {
        val node = p.codec.readTree<JsonNode>(p)
        // 读取type属性
        val type = node.get("type")?.asText()
        // 读取纯文本内容
        val text = if (node.isTextual) node.asText() else node.get("")?.asText()
        // 读取numerusform子节点
        val numerusForms = node.findValues("numerusform").map {
            NumerusForm(it.asText())
        }
        return Translation(type, text, numerusForms)
    }
}

然后给Translation类加上注解指定反序列化器即可:

@JsonDeserialize(using = TranslationDeserializer::class)
@JsonIgnoreProperties(ignoreUnknown = true)
data class Translation(
    // 字段定义保持不变
)

效果验证

调整后两种结构都可以正常解析:

  • 普通格式<translation>One</translation>:text字段值为One,numerusForm为空列表
  • 复数格式<translation><numerusform>Thing</numerusform>...</translation>:text字段为null,numerusForm为对应复数条目列表

内容的提问来源于stack exchange,提问作者Robert Jones

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.09 14:06:03