使用Jackson XML使用自定义条目名称反序列化Map

问题描述

我有一个XML文档要与Jackson反序列化:

<root>
  <properties>
    <property>
      <key>k1</key>
      <value>v1<value>
    </property>
  </properties>
</root>

如您所见,/root/properties非常像一张地图,每个/root/properties/property都像一个Map.Entry

是否有一种无需创建自定义反序列化器即可创建POJO并将其反序列化为Map<String,String> 方法

我希望获得以下类似信息,但没有成功:

@JacksonXmlRootElement(localName = "root")
public class Root {
  @JacksonXmlElementWrapper(localName = "properties")
  public Map<String,String> properties;
}

我从中得到的错误是:

com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.lang.String` out of START_OBJECT token

解决方法

您可以使用JsonAnySetter批注:

import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;

import java.io.File;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

public class XmlMapperApp {

    public static void main(String... args) throws Exception {
        File xmlFile = new File("./resource/test.xml").getAbsoluteFile();

        XmlMapper mapper = XmlMapper.xmlBuilder().build();
        Root root = mapper.readValue(xmlFile,Root.class);
        System.out.println(root.getProperties());
    }
}

@JacksonXmlRootElement(localName = "root")
class Root {

    @JsonIgnore
    private Map<String,String> properties = new LinkedHashMap<>();

    @JsonAnySetter
    public void setAllProperties(String value,List<Map<String,String>> xmlProperties) {
        if (xmlProperties == null) {
            return;
        }
        this.properties = xmlProperties.stream().reduce(new LinkedHashMap<>(),(l,r) -> {
            l.put(r.get("key"),r.get("value"));
            return l;
        });
    }

    public Map<String,String> getProperties() {
        return properties;
    }
}

上面XML上的代码打印出来:

{k1=v1}