Map节点的名称变更
Map节点的名称变更
改造需要的代码量比较多,因为JAXB原生不指定Map的自定义操作。也可以说JAXB不支持Map这种数据类型。所以需要使用到适配器来扩展Jaxb的功能。
首先定义一个类,其中只有两个字段,为了简单,可以不写setters/getters方法。通过这种方式模拟一个Map,只包含key/value,也就是first/second,这个名称就是XML的节点显示名称。
public class XmlMap {
public String first;
public String second;
}
自定义一个Adapter
,这里将所有的代码都展示出来。
public class MapAdapter extends XmlAdapter<XmlMap[], Map<String, String>>{
@Override
public Map<String, String> unmarshal(XmlMap[] v) throws Exception {
Map<String, String> map = new HashMap<>();
for(int i=0;i<v.length;i++) {
XmlMap pairs = v[i];
map.put(pairs.first, pairs.second);
}
return map;
}
@Override
public XmlMap[] marshal(Map<String, String> v) throws Exception {
XmlMap[] xmlMap = new XmlMap[v.size()];
int index = 0;
for(Map.Entry<String, String> entry: v.entrySet()) {
XmlMap xm = new XmlMap();
xm.first = entry.getKey();
xm.second = entry.getValue();
xmlMap[index++] = xm;
}
return xmlMap;
}
}
@XmlJavaTypeAdapter
JAXB能够内置支持List和Set集合,但是对于Map的支持需要自己处理。它继承自抽象类XmlAdapter<ValueType,BoundType>
类型参数:
- BoundType JAXB 不知道如何处理的一些类型。自定义的类型,告诉Jaxb ValueType 将此类型用作内存表示形式。
- ValueType JAXB 无需其他操作便知道如何处理的类型。
这里的Map对于JAXB是一个未知类型,但是XmlMap[]
却是已知的对象数组类型。通过中间的转化赋值,可以使XmlMap[]
与Map
相互转化,从而让Jaxb知道数据如何处理。
在之前的Product中,在Map上加上注解@XmlJavaTypeAdapter(MapAdapter.class)
。
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Product2 {
private String id;
@XmlJavaTypeAdapter(MapAdapter.class)
public Map<String, String> category;
// setters, getters
测试一下:
@Test
public void test2() throws JAXBException {
Map<String, String> map = new HashMap<>();
map.put("衣服", "大衣");
map.put("裤子", "西裤");
Product2 product = new Product2();
product.setId("1402");
product.setCategory(map);
JAXB.marshal(product, System.out);
}
得到的结果:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<product2>
<id>1402</id>
<category>
<item>
<first>衣服</first>
<second>大衣</second>
</item>
<item>
<first>裤子</first>
<second>西裤</second>
</item>
</category>
</product2>
上面的所有节点名称除了item
都是可以通过一定的方法改变的。