JAXB 使用 XML 适配器读取地图

JAXB Use XML Adapter to Read in Map

我正在尝试实施 this,其中

<SomeXml>
   <SomeData>...</SomeData>
   <InputData>
       <Param key="key1" value="value1" />
       <Param key="key2" value="value2" />
   </InputData>
   <OutputData>
       <Param key="key3" value="value3" />
   </OutputData>
</SomeXml>

变成

public class SomeXml {
    private SomeData someData;
    private Map<String, String> inputData;
    private Map<String, String> outputData;
}

其中 inputData 映射具有 (key1, value1), (key2, value2) 并且 outputData 映射具有 (key3, value3)。

这是我写的;

@NoArgsConstructor
@AllArgsConstructor
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement
public class MapElement {

    @XmlAttribute(name = "key')
    private String key;

    @XmlAttribute(name = "value")
    private String value;
}

@NoArgsConstructor
public class MapAdapter extends XmlAdapter<MapElement[], Map<String, String>> {

    public MapElement[] marshal(Map<String, String> args) throws Exception {
        MapElement[] mapElements = new mapElement[args.size()];
        int i = 0;
        for (Map.Entry<String, String> entry : args.entrySet()) {
            mapElements[i++] = new MapElement(entry.getKey(), entry.getValue());
        }

        return mapElements;
    }

    public Map<String, String> unmarshal(MapElement[] args) throws Exception {
        Map<String, String> m = new TreeMap<>();
        for (MapElement elem : args) {
            m.put(elem.getKey(), elem.getValue());
        }
        return m;
    }
}    

@NoArgsConstructor
@AllArgsConstructor
@XmlAccessorType(XmlAccessorType.FIELD)
@XmlRootElement
public class SomeXml {

    @XmlElement
    private SomeData someData;

    @XmlJavaAdapter(MapAdapter.class)
    @XmlElement(name = "InputData")
    private Map<String, String> inputData;

    @XmlJavaAdapter(MapAdapter.class)
    @XmlElement(name = "OutputData")
    private Map<String, String> outputData;
}

据我设法确定,InputData 和 OutputData 映射是非空的,因此正在创建它们,但是在检查 MapAdapter.unmarshal 函数的参数长度时,它为零,这意味着我无法正确读取标记信息。任何帮助将不胜感激。

在您的 posted 代码中,您的 SomeXml class 看起来很不完整, 因为它缺少所需的 JAXB 注释。 我不知道这些注释是否也丢失了 在您的真实代码中,或者如果您只是忘记在此处将它们写在 post 中。 不管怎样,注释应该是这样的:

@Getter
@Setter
@XmlRootElement(name = "SomeXml")
@XmlAccessorType(XmlAccessType.FIELD)
public class SomeXml {
    @XmlElement(name = "SomeData")
    private SomeData someData;
    
    @XmlElement(name = "InputData")
    @XmlJavaTypeAdapter(MapAdapter.class)
    private Map<String, String> inputData;

    @XmlElement(name = "OutputData")
    @XmlJavaTypeAdapter(MapAdapter.class)
    private Map<String, String> outputData;
}

我的第一个建议是:
从调试 marshalling 部分开始, 因为这比调试 unmarshalling 部分容易得多。 通过这样做,您将发现并解决代码中的一些问题 这也会破坏你的解组。

我用下面的测试代码做了这个

SomeXml someXml = new SomeXml();
someXml.setSomeData(new SomeData());
Map<String, String> inputData = new HashMap<>();
inputData.put("key1", "value1");
inputData.put("key2", "value2");
someXml.setInputData(inputData);
Map<String, String> outputData = new HashMap<>();
outputData.put("key3", "value3");
outputData.put("key4", "value4");
someXml.setOutputData(outputData);
    
JAXBContext context = JAXBContext.newInstance(SomeXml.class);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(someXml, System.out);

并得到以下 XML 输出:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<SomeXml>
    <SomeData/>
    <InputData>
        <item key="key1" value="value1"/>
        <item key="key2" value="value2"/>
    </InputData>
    <OutputData>
        <item key="key3" value="value3"/>
        <item key="key4" value="value4"/>
    </OutputData>
</SomeXml>

在这里您可以看到您的 MapAdapter class 在编组方面做得很好。 但有一个问题。编组的 XML 输出有 <item .../> 个元素 而不是想要的 <Param .../> 元素。 由此您还可以得出结论:您的解组代码没有处理 <Param ... /> 个元素,因为它需要 <item ... /> 个元素。

所以你有两个选择:

  • 更改 XML 输入以使用 <item> 而不是 <Param>
  • 告诉 JAXB 您的 MapElement class 对应于 <Param> XML 元素。 我留给你来解决这个细节。