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

如何通过Jackson XmlMapper反序列化带条目包装元素的XML Map?

解决Jackson XML反序列化带包装条目的Map结构问题

是的,可以实现这种XML结构的反序列化。你遇到的问题源于对@JacksonXmlElementWrapper的用法误解——这个注解的作用是给集合/Map添加外层包装元素,而非指定每个条目的元素名。要处理<MyEntry>包裹键值对的结构,只需结合MixIn(因无法修改原POJO)和Jackson XML模块的配置即可。

解决方案步骤

1. 配置XmlMapper的XML模块

通过DefaultXmlModule指定Map条目、键、值对应的XML元素名,让Jackson明确如何映射<MyEntry>、<Key>、<Value>到Map的键值对:

XmlMapper xmlMapper = new XmlMapper();
DefaultXmlModule xmlModule = new DefaultXmlModule();
// 指定Map的每个条目对应XML元素名:MyEntry
xmlModule.setMapEntryName("MyEntry");
// 指定Map键对应XML元素名:Key
xmlModule.setMapKeyName("Key");
// 指定Map值对应XML元素名:Value
xmlModule.setMapValueName("Value");
xmlMapper.registerModule(xmlModule);
// 保持默认的未知属性校验
xmlMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true);

2. 使用MixIn补充必要注解

因无法修改原MyRoot类,创建MixIn类给myMap字段添加注解,告知Jackson<MyMap>是Map的外层容器,且内部直接包含条目元素(无需额外包装):

abstract class MyRootMixIn {
    @JacksonXmlProperty(localName = "MyMap")
    @JacksonXmlElementWrapper(useWrapping = false) // 禁用Jackson自动生成的Map外层包装,<MyMap>已作为外层
    Map<String, String> myMap;

    @JacksonXmlProperty(localName = "MyString")
    String myString;
}

给XmlMapper注册该MixIn:

xmlMapper.addMixIn(MyRoot.class, MyRootMixIn.class);

3. 验证修改后的测试代码

更新测试逻辑,应用上述配置后即可正确解析XML:

@Test
public void reproducesDeserializationIssue() throws JsonProcessingException {
    XmlMapper xmlMapper = new XmlMapper();
    DefaultXmlModule xmlModule = new DefaultXmlModule();
    xmlModule.setMapEntryName("MyEntry");
    xmlModule.setMapKeyName("Key");
    xmlModule.setMapValueName("Value");
    xmlMapper.registerModule(xmlModule);
    xmlMapper.addMixIn(MyRoot.class, MyRootMixIn.class);
    xmlMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true);

    MyRoot myRoot = xmlMapper.readValue(XML, MyRoot.class);
    assertEquals("abc", myRoot.getMyString());
    assertEquals(2, myRoot.getMyMap().size()); // 正确识别2个条目
    assertEquals("value1", myRoot.getMyMap().get("key1"));
    assertEquals("value2", myRoot.getMyMap().get("key2"));
    
    // 序列化验证:输出符合原XML结构
    System.out.println(xmlMapper.writeValueAsString(myRoot));
}

原代码出错原因

原代码中,Jackson默认将<MyMap>下的<MyEntry>当作Map的键,值为空字符串——因为它不知道<MyEntry>内部的<Key>和<Value>才是真正的键值对。通过模块配置指定键值元素名,再结合MixIn禁用多余包装,就能让Jackson正确解析嵌套结构。

额外说明

如果需要处理更复杂的键值类型,可自定义Map反序列化器,但上述方案无需编写自定义逻辑,完全符合你“仅配置XmlMapper和使用MixIn”的需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 10:32:37