2012-11-19 58 views
2

假设我们有一个类测试,如:反序列化最终名单属性

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(); 
} 

我们看到了一个N​​ullPointerException,因为list没有初始化。

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

回答

0

XStream的使用以增强模式被改写的构造函数(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); 
    } 
} 
} 
+0

谢谢!你的第一个建议工作很好。我使用'PureJavaReflectionProvider'。另外我必须编写一个私有构造函数,它用'null'初始化没有被声明初始化的字段,在这种情况下是'name'。尽管'name'用'null'初始化,但XStream能够将其设置为'“XYZ”'。构造函数的属性是私有的,这是一个让字段最终确定的优雅方法。 – Vertex

0

请使用XStream Annotations and a custom 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(); 

} 

因此,例如,anoth在你的模型ER类可能是这样的:

public class Foo implements Listable{ 

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

     ... omissis ... 

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

    } 
+0

谢谢!当我尝试这个解决方案时,我感到困惑。你用'@XStreamConverter(ListableConverter.class)'注解了字段'list'。 'ListableConverter'不能转换'ArrayList',但只能'Listable's。要么我必须写1)'转换器'的孔类或2)'列表'。与1)我必须为每个类写一个自己的'Converter';与2),'unmarshal'永远不会被调用,因为XML中没有''元素。 – Vertex