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

Kotlin使用Jackson反序列化Last.fm API XML列表字段失败求助

解决Kotlin中Jackson反序列化Last.fm XML未包装列表的问题

看起来你已经摸到了问题的核心——Jackson对未包装XML列表的处理,加上Kotlin数据类的特性,导致了这个解析错误。我帮你梳理下关键问题点和修复方案:

问题根源分析

你的报错信息显示Jackson试图把一个字符串值(比如Flash \Flash Gordon's Theme\"")直接实例化Track类,这说明:

  1. 你没有正确标记RecentTracks中的XML属性(user、page等都是<recenttracks>标签的属性,不是子元素),导致Jackson解析结构混乱,误把列表元素的内容当成了属性值。
  2. 当XML中只有单个<track>时,Jackson默认不会将其识别为List,需要配置兼容单元素/多元素的场景。
  3. Track类中直接映射带属性的<artist>、<album>元素时,Jackson无法正确提取文本内容。

具体修复步骤

1. 修正RecentTracks的数据类注解

给XML属性字段加上@JacksonXmlProperty(isAttribute = true),同时确保列表的注解正确:

data class RecentTracks(
    @JacksonXmlProperty(isAttribute = true) val user: String = "",
    @JacksonXmlProperty(isAttribute = true) val page: Int = -1,
    @JacksonXmlProperty(isAttribute = true, localName = "perPage") val perPage: Int = -1,
    @JacksonXmlProperty(isAttribute = true, localName = "totalPages") val totalPages: Int = -1,
    @JacksonXmlProperty(isAttribute = true) val total: Int = -1,
    @JacksonXmlProperty(localName = "track")
    @JacksonXmlElementWrapper(useWrapping = false)
    val track: List<Track>? = null
)

2. 修正Track类的字段映射

因为<artist>和<album>都带有mbid属性,你有两种处理方式:

  • 方式一:只提取文本内容(如果你不需要mbid属性)
data class Track(
    val name: String = "",
    @JacksonXmlProperty(localName = "artist")
    @JacksonXmlText
    val artist: String = "",
    @JacksonXmlProperty(localName = "album")
    @JacksonXmlText
    val album: String = ""
)
  • 方式二:完整处理属性和文本(更严谨,保留mbid)
data class Track(
    val name: String = "",
    @JacksonXmlProperty(localName = "artist") val artist: Artist = Artist(),
    @JacksonXmlProperty(localName = "album") val album: Album = Album()
)

data class Artist(
    @JacksonXmlText val value: String = "",
    @JacksonXmlProperty(isAttribute = true) val mbid: String = ""
)

data class Album(
    @JacksonXmlText val value: String = "",
    @JacksonXmlProperty(isAttribute = true) val mbid: String = ""
)

3. 配置XmlMapper兼容单元素列表

添加ACCEPT_SINGLE_VALUE_AS_ARRAY配置,确保单个<track>也能被解析为List:

object Api {
    fun getRecentTracks(): RecentTracks {
        val module = JacksonXmlModule()
        module.setDefaultUseWrapper(false);
        val xmlMapper = XmlMapper(module).apply {
            registerKotlinModule()
            configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
            configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true)
            // 关键配置:允许将单个元素当作数组解析
            configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true)
        }
        val params = hashMapOf("user" to "eidsonator")
        val out = Http.getRequest("user.getrecenttracks", params)
        val stream = ByteArrayInputStream(out.toByteArray())
        return xmlMapper.readValue(stream, RecentTracks::class.java)
    }
}

为什么这样修复?

  • 标记XML属性后,Jackson能正确区分<recenttracks>的属性和子元素,不会混淆解析逻辑。
  • ACCEPT_SINGLE_VALUE_AS_ARRAY解决了单元素/多元素列表的兼容问题,避免Jackson在只有一个<track>时把它当成单个对象而非List。
  • 正确映射带属性的元素,确保Jackson能提取到你需要的文本内容,而不是错误地把元素当成字符串处理。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 08:28:11