我仍在研究更好的解决方案,但使用MOXy JAXB,我已经能够处理以下 XML:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<mapProperty>
<map>
<key>value</key>
<key2>value2</key2>
</map>
</mapProperty>
</root>
您需要在 Map 属性上使用 @XmlJavaTypeAdapter:
import java.util.HashMap;
import java.util.Map;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
@XmlRootElement
public class Root {
private Map<String, String> mapProperty;
public Root() {
mapProperty = new HashMap<String, String>();
}
@XmlJavaTypeAdapter(MapAdapter.class)
public Map<String, String> getMapProperty() {
return mapProperty;
}
public void setMapProperty(Map<String, String> map) {
this.mapProperty = map;
}
}
XmlAdapter 的实现如下:
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class MapAdapter extends XmlAdapter<AdaptedMap, Map<String, String>> {
@Override
public AdaptedMap marshal(Map<String, String> map) throws Exception {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document document = db.newDocument();
Element rootElement = document.createElement("map");
document.appendChild(rootElement);
for(Entry<String,String> entry : map.entrySet()) {
Element mapElement = document.createElement(entry.getKey());
mapElement.setTextContent(entry.getValue());
rootElement.appendChild(mapElement);
}
AdaptedMap adaptedMap = new AdaptedMap();
adaptedMap.setValue(document);
return adaptedMap;
}
@Override
public Map<String, String> unmarshal(AdaptedMap adaptedMap) throws Exception {
Map<String, String> map = new HashMap<String, String>();
Element rootElement = (Element) adaptedMap.getValue();
NodeList childNodes = rootElement.getChildNodes();
for(int x=0,size=childNodes.getLength(); x<size; x++) {
Node childNode = childNodes.item(x);
if(childNode.getNodeType() == Node.ELEMENT_NODE) {
map.put(childNode.getLocalName(), childNode.getTextContent());
}
}
return map;
}
}
AdpatedMap 类是所有魔法发生的地方,我们将使用 DOM 来表示内容。我们将通过 @XmlAnyElement 和 Object 类型的属性的组合来欺骗 JAXB 介绍处理 DOM:
import javax.xml.bind.annotation.XmlAnyElement;
public class AdaptedMap {
private Object value;
@XmlAnyElement
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
}
此解决方案需要 MOXy JAXB 实现。您可以将 JAXB 运行时配置为使用 MOXy 实现,方法是在模型类中添加一个名为 jaxb.properties 的文件,其中包含以下条目:
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
以下演示代码可用于验证代码:
import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Root.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
Root root = (Root) unmarshaller.unmarshal(new File("src/forum74/input.xml"));
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(root, System.out);
}
}