3

假设我们有一个类 Test 像:

public class Test {
    private final String name;
    private final List<String> list = new ArrayList<>();

    public Test(String name) {
        this.name = name;
    }

    void add(String s) {
        list.add(s);
    }

    void print() {
        System.out.println("name: " + name);
        for (String s : list) {
            System.out.println(" - " + s);
        }
    }
}

没有 XSteam 的不变量

this.list != null

每次都持有。

但是如果我们看一下第四个测试

public static void main(String[] args) {
    final XStream xstream = new XStream();
    xstream.alias("test", Test.class);

    // Serialize
    final Test test1 = new Test("XYZ");
    test1.add("One");
    test1.add("Two");

    //@formatter:off
    /* name: XYZ
     *  - One
     *  - Two
     */
    //@formatter:on
    test1.print();

    //@formatter:off
    /* <test>
     *   <name>XYZ</name>
     *   <list>
     *     <string>One</string>
     *     <string>Two</string>
     *   </list>
     * </test>
     */
    //@formatter:on
    System.out.println(xstream.toXML(test1));

    // Deserialize with one list entry
    final String xmlTest2 = "<test><name>XYZ</name><list><string>One</string></list></test>";
    final Test test2 = (Test) xstream.fromXML(xmlTest2);
    //@formatter:off
    /* <test>
     *   <name>XYZ</name>
     *   <list>
     *     <string>One</string>
     *   </list>
     * </test>
     */
    //@formatter:on
    test2.print();

    // Deserialize with empty list
    final String xmlTest3 = "<test><name>XYZ</name><list /></test>";
    final Test test3 = (Test) xstream.fromXML(xmlTest3);
    //@formatter:off
    /* name: XYZ
     */
    //@formatter:on
    test3.print();

    // Deserialize without list-tag
    final String xmlTest4 = "<test><name>XYZ</name></test>";
    final Test test4 = (Test) xstream.fromXML(xmlTest4);
    //@formatter:off
    /* name: XYZ
     * Exception in thead ... NullPointerException
     */
    //@formatter:on
    test4.print();
}

我们看到一个 NullPointerException,因为list没有初始化。

我想list在 XML 可选中包含与 test4 类似的 -element。我能做些什么?因为我的数据模型中有很多类类似于Test,所以我不想Converter为每个类都写一个。但是假设我会写一个Converter,我该如何设置最终属性name

4

2 回答 2

0

请使用 XStream Annotations 和自定义 Converter找到以下解决方案。

自定义转换器是以下类:

 public class ListableConverter implements Converter {

    public void marshal(Object source, HierarchicalStreamWriter writer,
            MarshallingContext context) {
        Listable listable = (Listable) source;
        writer.setValue(String.valueOf(... your marshalling logic here ...));
    }

    public Object unmarshal(HierarchicalStreamReader reader,
            UnmarshallingContext context) {
        List<String> list = new ArrayList<String>();
        // your unmarshalling logic here
        return list;
    }

    public boolean canConvert(Class type) {
        return type instanceof Listable;
    }
}

这是带有注释的修改后的测试类:

public class Test implements Listable{
    private final String name;

    @XStreamConverter(ListableConverter.class)
    private final List<String> list = new ArrayList<>();

    public List<String> getList() {
        return list;
    }

    public Test(String name) {
        this.name = name;
    }

    void add(String s) {
        list.add(s);
    }

    void print() {
        System.out.println("name: " + name);
        for (String s : list) {
            System.out.println(" - " + s);
        }
    }
}

最后,用于使转换器适用于模型中实现该接口的任何类的接口:

public interface Listable<String> {

    public List<String> getList();

}

因此,例如,模型中的另一个类可能如下所示:

    public class Foo implements Listable{

        @XStreamConverter(ListableConverter.class)
        private final List<String> anotherList = new ArrayList<>();

        ... omissis ...

        public List<String> getList() {
          return anotherList;
        }

   }
于 2012-11-19T17:34:09.323 回答
0

XStream 在增强模式(默认)下使用 munged 构造函数(http://stackoverflow.com/questions/1426106/why-are-constructors-returned-by-reflectionfactor-newconstructorforserialization)。您可以通过在纯模式下初始化 XStream 来更改此行为:

XStream xstream = new XStream(new PureJavaReflectionProvider());

另一种选择是使用 getter 访问变量并实现延迟初始化。

public class Test {
private final String name;
private List<String> list;

public Test(String name) {
    this.name = name;
}

void add(String s) {
    list.add(s);
}

List<String> getList() {
  if (list == null) {
    list = new ArrayList<>();
  }
  return list;
}

void print() {
    System.out.println("name: " + name);
    for (String s : getList()) {
        System.out.println(" - " + s);
    }
}
}
于 2012-11-19T18:23:28.537 回答