Kotlin使用Jackson反序列化Last.fm API XML列表字段失败求助
解决Kotlin中Jackson反序列化Last.fm XML未包装列表的问题
看起来你已经摸到了问题的核心——Jackson对未包装XML列表的处理,加上Kotlin数据类的特性,导致了这个解析错误。我帮你梳理下关键问题点和修复方案:
问题根源分析
你的报错信息显示Jackson试图把一个字符串值(比如Flash \Flash Gordon's Theme\"")直接实例化Track类,这说明:
- 你没有正确标记
RecentTracks中的XML属性(user、page等都是<recenttracks>标签的属性,不是子元素),导致Jackson解析结构混乱,误把列表元素的内容当成了属性值。 - 当XML中只有单个
<track>时,Jackson默认不会将其识别为List,需要配置兼容单元素/多元素的场景。 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
相关产品推荐
相关产品推荐

