簡體   English   中英

如何使用Xstream的addImplicitMap方法?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM