2016-03-07 31 views
1

我正在使用XStream 1.4.8并试图序列化一个通用的LinkedHashMap<?,?>XStream:Generic LinkedHashMap的问题

LinkedHashMap在由XStream序列化时似乎没有保持其顺序。我需要为它写一个新的转换器,以便它可以。

由于我有几种不同类型的Generic类LinkedHashMap正在使用,而且我想只需要一个适用于泛型版本的Converter,这个问题就加剧了。

换句话说: 给予一个任意的对象序列化可能包含几种不同类型的LinkedHashMap<?,?>类型,你怎么编组和取消编组所有这些,与用于每个仿制药的正确类型的字段,并与在每个LinkedHashMaps中维护的顺序?

这个问题是相似的,但它不是仿制药,并且也是基于旧版本的XStream的: Xstream does not maintain order of child elements while unmarshalling

回答

0

你可以在这个源代码的一些想法:

https://github.com/bluesoft-rnd/aperte-workflow-core/blob/master/core/activiti-context/src/main/java/org/aperteworkflow/ext/activiti/ActivitiStepAction.java#L47

Map params = new HashMap(); 
    if (this.params != null) { 
     String xml = (String) this.params.getValue(execution); 
     if (xml != null) { 
      XStream xs = new XStream(); 
      xs.alias("map", java.util.Map.class); 
      xs.registerConverter(new Converter() { 
       public boolean canConvert(Class clazz) { 
        return AbstractMap.class.isAssignableFrom(clazz); 
       } 

       public void marshal(Object value, HierarchicalStreamWriter writer, MarshallingContext context) { 
        AbstractMap<String, String> map = (AbstractMap<String, String>) value; 
        for (Map.Entry<String, String> entry : map.entrySet()) { 
         writer.startNode(entry.getKey().toString()); 
         writer.setValue(entry.getValue().toString()); 
         writer.endNode(); 
        } 
       } 

       public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { 
        Map<String, String> map = new HashMap<String, String>(); 

        while (reader.hasMoreChildren()) { 
         reader.moveDown(); 
         map.put(reader.getNodeName(), reader.getValue()); 
         reader.moveUp(); 
        } 
        return map; 
       } 
      }); 
      params = (Map) xs.fromXML(xml); 
     } 
    } 
+0

仅当Map始终为类型时才有效。一般情况如何? –

0

这里的一些例子:

/** 
* Checks whether the XStream-based REST converters should be used for 
* rendering the response of this REST request. 
* <p> 
* This method checks whether the request has a query attribute named 
* <tt>"rest"</tt>, or whether there is a system-wide 
* {@link BundleProperties#getProperty(String) bundle/system property} 
* named <tt>"skalli.rest"</tt> with a value <i>different</i> from <tt>"v1"</tt>. 
* In that case, e.g. the request has a query attribute <tt>"rest=v2"</tt>, 
* the method returns <code>false</code> to indicate that the new 
* RestWriter-based converters should be employed. Otherwise the 
* method returns <code>true</code>. 
* <p> 
* If the requested media type is different from <tt>"text/xml"</tt>, 
* always <code>false</code> will be returned. 
* 
* @return <code>true</code>, if XStream-based converters should be used 
* for rendering the response of this REST request. 
*/ 
@SuppressWarnings("nls") 
protected boolean enforceOldStyleConverters() { 
    if (!context.isXML()) { 
     return false; 
    } 
    String restVersion = getQueryAttribute("rest"); 
    if (StringUtils.isBlank(restVersion)) { 
     restVersion = BundleProperties.getProperty("skalli.rest"); 
    } 
    if (StringUtils.isNotBlank(restVersion)) { 
     return "v1".equalsIgnoreCase(restVersion); 
    } 
    return true; 
} 

完整的源代码在这里:

http://code.openhub.net/file?fid=FMrVl1G9kYhg416Lk5dachOp98c&cid=br-mQGOdySQ&s=XStream%3A%20problems%20with%20Generic%20LinkedHashMap&pp=0&fl=Java&ff=1&filterChecked=true&fp=390342&mp,=1&ml=1&me=1&md=1&projSelected=true#L0

+0

我不明白这与LinkedHashMaps或处理泛型有什么关系。您的链接似乎只是将我的问题输入搜索引擎的结果,并且与此无关。 –

0

一些试验和错误之后,我找到了解决办法。对于任何感兴趣的人来说,这里是:

事实证明,泛型类实际上并不像我担心的那么多。具有讽刺意味的是,Java的编译时解释通常很烦人,最终导致我们在这里受益:实际上只需创建一个只有Object作为泛型的LinkedHashMap。

但是,需要注意确保存储在地图中的对象被解组为正确的类。只需存储地图每个条目的类信息即可轻松完成此操作。请注意,仅为整个地图存储一次类信息是不够的,因为地图的某些条目可能是该类的子类。

private static class LinkedHashMapConverter implements Converter { 
    @SuppressWarnings("rawtypes") 
    @Override 
    public boolean canConvert(Class clazz) { 
     return clazz.equals(LinkedHashMap.class); 
    } 

    @Override 
    public void marshal(Object value, HierarchicalStreamWriter writer, MarshallingContext context) { 
     @SuppressWarnings("unchecked") 
     LinkedHashMap<Object, Object> map = (LinkedHashMap<Object, Object>) value; 
     // store each entry 
     for (Entry<Object, Object> a : map.entrySet()) { 
      writer.startNode("entry"); 
      // store the key, the value, and the types of both 
      writer.startNode("keyClass"); 
      context.convertAnother(a.getKey().getClass()); 
      writer.endNode(); 
      writer.startNode("key"); 
      context.convertAnother(a.getKey()); 
      writer.endNode(); 
      writer.startNode("valueClass"); 
      context.convertAnother(a.getValue().getClass()); 
      writer.endNode(); 
      writer.startNode("value"); 
      context.convertAnother(a.getValue()); 
      writer.endNode(); 
      writer.endNode(); 
     } 
    } 

    @SuppressWarnings("rawtypes") 
    @Override 
    public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { 
     LinkedHashMap<Object, Object> res = new LinkedHashMap<Object, Object>(); 
     while (reader.hasMoreChildren()) { 
      reader.moveDown(); 
      // load the key, the value, and the types of both 
      reader.moveDown(); 
      Class keyClass = (Class) context.convertAnother(res, Class.class); 
      reader.moveUp(); 
      reader.moveDown(); 
      Object key = context.convertAnother(res, keyClass); 
      reader.moveUp(); 
      reader.moveDown(); 
      Class valueClass = (Class) context.convertAnother(res, Class.class); 
      reader.moveUp(); 
      reader.moveDown(); 
      Object value = context.convertAnother(res, valueClass); 
      reader.moveUp(); 
      res.put(key, value); 
      reader.moveUp(); 
     } 
     return res; 
    } 
}