如何在XStream中处理循环引用?

时间:2015-01-05 10:28:39

标签: java serialization xml-serialization xstream

XStream serialization library声称在开箱即用的序列化复杂Java对象方面是健壮的(例如,不需要修改对象或映射)。特别是,根据XStream docs,XStream可以处理循环对象引用。

所以我写了一个测试来检查这个 - 我试图序列化一个有点复杂的数据结构(LinkedHashMultimap),其中包含对iteself的引用:

import com.google.common.collect.LinkedHashMultimap;
import com.thoughtworks.xstream.XStream;

public class SerializationTest {

    public static void main(String[] args0) {

        // Create LinkedHashMultimap to serialize
        LinkedHashMultimap<String, Object> outObj = LinkedHashMultimap.create();
        outObj.put("x", 1);
        outObj.put("x", "abc");
        outObj.put("y", outObj);   // Add a self-reference

        // Try to serialize
        XStream xstream = new XStream();
        String xml = xstream.toXML(outObj);
        System.out.println(xml);  // Print XML to console for a quick peek

        // Try to deserialize - ERROR HERE!!!
        LinkedHashMultimap<String, Object> inObj = (LinkedHashMultimap<String, Object>)xstream.fromXML(xml);

        System.out.println(inObj);
    }
}

序列化的XML对象如下所示:

<com.google.common.collect.LinkedHashMultimap serialization="custom">
  <unserializable-parents/>
  <com.google.common.collect.LinkedHashMultimap>
    <default/>
    <int>2</int>
    <int>2</int>
    <string>x</string>
    <string>y</string>
    <int>3</int>
    <string>x</string>
    <int>1</int>
    <string>x</string>
    <string>abc</string>
    <string>y</string>
    <com.google.common.collect.LinkedHashMultimap reference="../.."/>
  </com.google.common.collect.LinkedHashMultimap>
</com.google.common.collect.LinkedHashMultimap>

但是,反序列化(即对xstream.fromXML()的调用)失败并显示NullPointerException例外:

Exception in thread "main" com.thoughtworks.xstream.converters.ConversionException: Could not call com.google.common.collect.LinkedHashMultimap.readObject() : null
---- Debugging information ----
message             : Could not call com.google.common.collect.LinkedHashMultimap.readObject()
cause-exception     : java.lang.NullPointerException
cause-message       : null
class               : com.google.common.collect.LinkedHashMultimap
required-type       : com.google.common.collect.LinkedHashMultimap
converter-type      : com.thoughtworks.xstream.converters.reflection.SerializableConverter
path                : /com.google.common.collect.LinkedHashMultimap/com.google.common.collect.LinkedHashMultimap
line number         : 15
version             : 1.4.7
-------------------------------
    at com.thoughtworks.xstream.converters.reflection.SerializationMethodInvoker.callReadObject(SerializationMethodInvoker.java:119)
    at com.thoughtworks.xstream.converters.reflection.SerializableConverter.doUnmarshal(SerializableConverter.java:454)
    at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshal(AbstractReflectionConverter.java:257)
    at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72)
    at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:65)
    at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66)
    at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:50)
Disconnected from the target VM, address: '127.0.0.1:50107', transport: 'socket'
    at com.thoughtworks.xstream.core.TreeUnmarshaller.start(TreeUnmarshaller.java:134)
    at com.thoughtworks.xstream.core.AbstractTreeMarshallingStrategy.unmarshal(AbstractTreeMarshallingStrategy.java:32)
    at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:1185)
    at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:1169)
    at com.thoughtworks.xstream.XStream.fromXML(XStream.java:1040)
    at com.thoughtworks.xstream.XStream.fromXML(XStream.java:1031)
    at SerializationTest3.main(SerializationTest3.java:18)
Caused by: java.lang.NullPointerException
    at com.google.common.collect.AbstractMapBasedMultimap$AsMap.hashCode(AbstractMapBasedMultimap.java:1289)
    at com.google.common.collect.AbstractMultimap.hashCode(AbstractMultimap.java:228)
    at com.google.common.collect.LinkedHashMultimap.hashCode(LinkedHashMultimap.java:81)
    at com.google.common.collect.Hashing.smearedHash(Hashing.java:51)
    at com.google.common.collect.LinkedHashMultimap$ValueSet.add(LinkedHashMultimap.java:416)
    at com.google.common.collect.LinkedHashMultimap.readObject(LinkedHashMultimap.java:574)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at com.thoughtworks.xstream.converters.reflection.SerializationMethodInvoker.callReadObject(SerializationMethodInvoker.java:113)
    ... 13 more

所以有人知道为什么会这样吗?以及如何解决这个问题?

1 个答案:

答案 0 :(得分:1)

使用:

XStream xstream = new XStream();
xstream.setMode(XStream.XPATH_RELATIVE_REFERENCES);