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

毎回持ちます。

しかし、4番目のテストを見ると

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されます。

listtest4 と同様に、XML オプションの - 要素を使用したいと思います。私に何ができる?私のデータモデルには に似たクラスがたくさんあるので、すべてのクラスTestに for を書きたくありませんConverter。しかしConverter、どうすれば final 属性を設定できる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;
    }
}

これは、アノテーションを使用して変更された Test クラスです。

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 は拡張モード (デフォルト) で変更されたコンストラクター (http://stackoverflow.com/questions/1426106/why-are-constructors-returned-by-reflectionfactor-newconstructorforserialization) を使用します。XStream をピュア モードで初期化することにより、この動作を変更できます。

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

もう 1 つのオプションは、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 に答える