2014-09-01 80 views
2

我想要用xStream序列化BiMap。由於我不喜歡由BiStream自動生成的xStream代碼,我認爲將BiMap轉換爲HashMap並序列化HashMap或反序列化時可能是一個好主意,我只需再次讀入HashMap並將其轉換回來到BiMap。所以我想出了以下轉換器策略:使用xStream序列化BiMap

public class XStreamBiMapConverterExample 
{ 
    public void run() 
    { 
    XStream xStream = new XStream(); 
    xStream.setMode(XStream.XPATH_ABSOLUTE_REFERENCES); 
    xStream.registerConverter(new BiMapConverter(), XStream.PRIORITY_VERY_HIGH); 

    final String xml = xStream.toXML(new ObjectToSerialize()); 

    System.out.println(xml); 

    xStream.fromXML(xml);//Reading does not work, if the BiMap of ObjectToSerialize is empty 
    } 

    public static void main(final String[] args) 
    { 
    new XStreamBiMapConverterExample().run(); 
    } 
} 


class ObjectToSerialize 
{ 
    // Map<String, Integer> serializeMap = new HashMap<>(); 
    BiMap<String, Integer> serializeMap = HashBiMap.create(); 

    public ObjectToSerialize() 
    { 
    //If there is no Values, my Converter fails. With Value there is no Problem. 
    // serializeMap.put("Hallo", 7); 
    } 
} 


class BiMapConverter implements Converter 
{ 
    @Override 
    public boolean canConvert(@SuppressWarnings("rawtypes") final Class type) 
    { 
    return BiMap.class.isAssignableFrom(type); 
    } 

    @Override 
    public void marshal(final Object source, final HierarchicalStreamWriter writer, 
         final MarshallingContext context) 
    { 
    final BiMap<?, ?> biMap = (BiMap<?, ?>) source; 

    final HashMap<?, ?> convertBiMapToHashMap = convertMapToHashMap(biMap); 

    context.convertAnother(convertBiMapToHashMap); 
    } 

    private <K, V> HashMap<K, V> convertMapToHashMap(final Map<K, V> map) 
    { 
    final HashMap<K, V> hashMap = new HashMap<>(); 

    for (Entry<K, V> entry : map.entrySet()) 
    { 
     hashMap.put(entry.getKey(), entry.getValue()); 
    } 

    return hashMap; 
    } 

    @Override 
    public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) 
    { 
    final HashMap<?, ?> serializedMap = 
     (HashMap<?, ?>) context.convertAnother(reader.getValue(), HashMap.class); 

    return convertMapToBiMap(serializedMap); 
    } 

    private <K, V> BiMap<K, V> convertMapToBiMap(final Map<K, V> map) 
    { 
    final BiMap<K, V> biMap = HashBiMap.create(); 

    for (Entry<K, V> entry : map.entrySet()) 
    { 
     biMap.put(entry.getKey(), entry.getValue()); 
    } 

    return biMap; 
    } 
} 

這工作得很好,因爲xStream已經可以轉換HashMaps了。奇怪的是,它只有在BiMap中有值時才起作用。如果BIMAP是空的,我得到下面的異常,在解組數據:

Exception in thread "main" com.thoughtworks.xstream.converters.ConversionException: only START_TAG can have attributes END_TAG seen ...ize>\n <serializeMap class="com.google.common.collect.HashBiMap"/>... @2:62 : only START_TAG can have attributes END_TAG seen ...ize>\n <serializeMap class="com.google.common.collect.HashBiMap"/>... @2:62 
---- Debugging information ---- 
message    : only START_TAG can have attributes END_TAG seen ...ize>\n <serializeMap class="com.google.common.collect.HashBiMap"/>... @2:62 
cause-exception  : java.lang.IndexOutOfBoundsException 
cause-message  : only START_TAG can have attributes END_TAG seen ...ize>\n <serializeMap class="com.google.common.collect.HashBiMap"/>... @2:62 
class    : com.google.common.collect.HashBiMap 
required-type  : com.google.common.collect.HashBiMap 
converter-type  : BiMapConverter 
path    : /ObjectToSerialize/serializeMap 
line number   : 2 
class[1]   : ObjectToSerialize 
converter-type[1] : com.thoughtworks.xstream.converters.reflection.ReflectionConverter 
version    : 1.4.6 
------------------------------- 
    at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:79) 
    at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:65) 
    at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66) 
... 

使用轉換器(!當BIMAP爲空)後生成的輸出如下:

<ObjectToSerialize> 
    <serializeMap class="com.google.common.collect.HashBiMap"/> 
</ObjectToSerialize> 

誰能告訴我,我做錯了什麼?

回答

2

您不需要撥打unmarshal方法中的reader.getValue()

public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { 
    final HashMap<?, ?> serializedMap = (HashMap<?, ?>) context.convertAnother(null, HashMap.class); 
    return convertMapToBiMap(serializedMap); 
} 

這將與一個空的地圖工作。

+0

作品很有魅力,謝謝!猜猜我必須深入挖掘API以瞭解,爲什麼這是行得通的。 – crusam 2014-09-02 07:34:02

+0

謝謝我很好奇你是怎麼想出來的?這個功能沒有javadoc! – Hunsu 2015-04-04 12:18:43

+0

'getValue()'將解析器推進到元素的結束標記。之後,沒有屬性可以被讀取,因此錯誤。非常模糊。 – 2015-04-16 21:21:29

相關問題