[英]How to use addImplicitMap method of Xstream?
我想在其中可用的addImplicitMap方法的幫助下使用xstream序列化該類。 類將如下所示:
class MapTest{
private Map<String, String> mapList;
public MapTest() {
mapList= new HashMap<String, String>();
}
public void setServicesHealth(String id, String name) {
map.put(id, name);
}
我嘗試像:
class MapTestMain{
public static void main(String args[]){
MapTest services = new MapTest();
services.setServicesHealth("ID01", "Jack");
services.setServicesHealth("ID02", "Neil);
XStream stream = new XStream(new StaxDriver());
stream.alias("MapTest", MapTest.class);
stream.addImplicitMap(MapTest.class, "map", "id", String.class, "name");
String xmlStr = stream.toXML(services);
System.out.println(xmlStr);
}
}
但是我沒有得到正確的輸出。 我的預期輸出是:
<?xml version="1.0" ?>
<MapTest>
<id>Started</id>
<name>Started</name>
</MapTest>
請幫我...
TLDR: addImplicitMap
不允許您刪除<mapList>
容器元素和entry
元素,並一次重命名鍵/值元素(示例1和2)。 要更好地控制地圖中元素的命名,請使用NamedMapConverter
(示例3)。 為了能夠一次完成所有操作,您將需要一個自定義的Converter
實現(示例4)。
長答案:
因此,關於addImplicitMap
似乎沒有很好的解釋,在他們的文檔中也不太清楚,因此我將在這里嘗試進行解釋。
addImplicitMap
將刪除容器元素,但是當像這樣使用時,它將不允許您刪除<entry>
元素或重命名鍵/值元素。 例如: (1)
stream.addImplicitMap(MapTest.class, "mapList", "s", Map.Entry.class, null);
結果是:
<MapTest>
<s>
<string>ID01</string>
<string>Jack</string>
</s>
<s>
<string>ID02</string>
<string>Neil</string>
</s>
</MapTest>
另外, addImplicitMap
允許您在寫入時僅存儲映射的值 (忽略容器元素和鍵元素)。 讀取XML時,它將使用值對象的指定字段重新創建映射鍵,因此映射鍵必須存儲在映射值對象中 。
例如,我們可以將地圖的值作為具有ID屬性的Service
對象,並使Xstream僅存儲值並根據它們重新創建地圖: (2)
private Map<String, Service> serviceMap; // modified in MapTest
static class Service {
private String id, name;
public Service(String id, String name) {
this.id = id;
this.name = name;
}
}
MapTest services = new MapTest();
services.setService("ID01", new Service("ID01", "Jack"));
services.setService("ID02", new Service("ID02", "Neil"));
stream.addImplicitMap(MapTest.class, "serviceMap", "s", Service.class, "id");
輸出:
<MapTest>
<s>
<id>ID01</id>
<name>Jack</name>
</s>
<s>
<id>ID02</id>
<name>Neil</name>
</s>
</MapTest>
請注意,這里每個<s>
元素實際上是序列化的Service
對象,而不是Map.Entry
對象。
這仍然不能完全解決您的問題(我們也必須更改地圖中的內容),因此我們可以嘗試使用namedMapConverter
。 如果我們像以前一樣使用<String, String>
的映射,則可以使用: (3)
stream.registerConverter(new NamedMapConverter(stream.getMapper(),
null, "id", String.class, "name", String.class));
給出輸出:
<MapTest>
<serviceMap>
<id>ID01</id>
<name>Jack</name>
<id>ID02</id>
<name>Neil</name>
</serviceMap>
</MapTest>
還沒完全正確的,我不相信你可以做的更好,而不實現自定義Converter
類(有一個很好的教程在這里 )。 因此,我們添加了這一行(而不是NamedMapConverter
):
stream.registerConverter(new MapTestConverter());
並使用自定義的Converter實現: (4)
static class MapTestConverter implements Converter {
public boolean canConvert(Class type) {
return type.equals(MapTest.class);
}
public void marshal(Object source, HierarchicalStreamWriter writer,
MarshallingContext context) {
MapTest mt = (MapTest) source;
for (Entry<String, String> e : mt.serviceMap.entrySet()) {
writer.startNode("id");
writer.setValue(e.getKey());
writer.endNode();
writer.startNode("name");
writer.setValue(e.getValue());
writer.endNode();
}
}
public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
MapTest mt = new MapTest();
String id = null;
while (reader.hasMoreChildren()) {
reader.moveDown();
if ("id".equals(reader.getNodeName())) {
if (id != null) { throw new RuntimeException("Malformed XML, ID was set twice: " + id); }
id = (String) context.convertAnother(mt, String.class);
} else if ("name".equals(reader.getNodeName())) {
String name = (String) context.convertAnother(mt, String.class);
if (id == null) { throw new RuntimeException("Malformed XML: Found name without ID: " + name); }
mt.serviceMap.put(id, name);
id = null;
}
reader.moveUp();
}
return mt;
}
}
最后,我們得到了預期的結果:
<MapTest>
<id>ID01</id>
<name>Jack</name>
<id>ID02</id>
<name>Neil</name>
</MapTest>
(對不起,我的代表不足,無法將以下內容放入鏈接中)
addImplicitMap
示例的完整代碼:pastebin.com/MYiAde3m
namedMapConverter
示例的完整代碼:pastebin.com/kVChup5x
Converter
示例的完整代碼:pastebin.com/vUTwaHkk
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.