如何使用Jackson将XML中带key属性的entry映射到POJO属性?
解决Jackson映射带key属性的XML到POJO的问题
我懂你现在的困扰——你要对接的旧系统返回的XML是<entry key="xxx">这种键值对结构,但你的POJO是平级的字段,Jackson默认没法自动把这两者对应起来对吧?别担心,我给你两种实用的解决方案,你可以根据自己的需求选:
方案一:借助中间Entry类映射后赋值
这种方式逻辑直观,容易理解和维护,适合大多数场景。我们先把所有<entry>元素解析成一个列表,再通过初始化方法把键值对映射到POJO的对应字段:
@JacksonXmlRootElement(localName = "properties") @Data public class Example { private String token; private String affid; private String domain; // 先将所有entry元素解析为列表,useWrapping=false表示不需要额外的包装标签 @JacksonXmlElementWrapper(useWrapping = false) @JacksonXmlProperty(localName = "entry") private List<Entry> entries; // 初始化方法,在Jackson完成对象实例化后自动执行,将entry的键值对映射到字段 @PostConstruct private void mapEntriesToFields() { if (entries == null) return; for (Entry entry : entries) { switch (entry.getKey()) { case "token": this.token = entry.getValue(); break; case "affid": this.affid = entry.getValue(); break; case "domain": this.domain = entry.getValue(); break; } } // 解析完成后清空列表,避免不必要的内存占用 this.entries = null; } // 内部类,用来单独映射单个entry元素的属性和文本值 @Data static class Entry { // 映射entry标签的key属性 @JacksonXmlProperty(isAttribute = true) private String key; // 映射entry标签的文本内容 @JacksonXmlText private String value; } }
方案二:自定义反序列化器直接映射字段
如果你不想引入额外的内部类,可以通过自定义反序列化器,让Jackson直接匹配对应key的entry元素到POJO字段:
@JacksonXmlRootElement(localName = "properties") @Data public class Example { @JacksonXmlProperty(localName = "entry") @JsonDeserialize(using = EntryValueDeserializer.class) @JsonProperty("token") private String token; @JacksonXmlProperty(localName = "entry") @JsonDeserialize(using = EntryValueDeserializer.class) @JsonProperty("affid") private String affid; @JacksonXmlProperty(localName = "entry") @JsonDeserialize(using = EntryValueDeserializer.class) @JsonProperty("domain") private String domain; // 自定义反序列化器,提取对应key的entry文本值 static class EntryValueDeserializer extends StdDeserializer<String> { public EntryValueDeserializer() { super(String.class); } @Override public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { JsonNode node = p.getCodec().readTree(p); String entryKey = node.get("@key").asText(); // 获取当前要映射的POJO字段名称(通过@JsonProperty指定) String targetFieldKey = ctxt.getParser().getCurrentName(); if (targetFieldKey.equals(entryKey)) { return node.asText(); } return null; } } }
测试代码
不管用哪种方案,你都可以用下面的代码测试解析是否成功:
public class XmlParsingDemo { public static void main(String[] args) throws IOException { String xmlContent = "<properties>\n" + " <entry key=\"token\">rent</entry>\n" + " <entry key=\"affid\">true</entry>\n" + " <entry key=\"domain\">example.com</entry>\n" + "</properties>"; XmlMapper xmlMapper = new XmlMapper(); Example result = xmlMapper.readValue(xmlContent, Example.class); System.out.println("Token: " + result.getToken()); System.out.println("Affid: " + result.getAffid()); System.out.println("Domain: " + result.getDomain()); } }
小提示:方案一更适合新手或者需要后续扩展字段的场景,逻辑清晰;方案二适合追求代码简洁、不想额外定义类的场景。
内容的提问来源于stack exchange,提问作者Jesse Nelson
相关产品推荐
相关产品推荐

