XStream序列化和反序列化中的多态性

时间:2012-07-14 14:28:22

标签: java xstream

我有这些课程:

@XStreamAlias("person")
public class PersonConfig {

    private AnimalConfig animalConfig;

}

public interface AnimalConfig {}

@XStreamAlias("dog");
public class DogConfig extend AnimalConfig {}

@XStreamAlias("cat");
public class CatConfig extend AnimalConfig {}

我希望能够使用上面的类反序列化这个xml:

<person>
    <dog/>
<person>

同样反序列化这个xml,使用相同的类:

<person>
    <cat/>
<person>

因此,在这两种情况下,PersonConfig的字段animalConfig都已填充。在带有DogConfig实例的第一个XML和带有CatConfig实例的第二个XML中。

这可以通过添加一些注释来实现吗?

4 个答案:

答案 0 :(得分:3)

似乎XStream不允许您轻松完成。

您的问题类似于this one,要求使用XStream管理类似xsd:choice的内容。

如果您不一定需要使用XStream,JAXB将允许您轻松完成:

@XmlRootElement(name="person")
public class PersonConfig {

    private AnimalConfig animalConfig;

    @XmlElementRefs({
        @XmlElementRef(name="cat", type=CatConfig.class),
        @XmlElementRef(name="dog", type=DogConfig.class)
    })
    public AnimalConfig getAnimalConfig() {
        return animalConfig;
    }

    public void setAnimalConfig(AnimalConfig animalConfig) {
        this.animalConfig = animalConfig;
    }
}

经过一些研究,如果您选择使用XmlAdapter,则可以避免列出您所有属性的所有可用类。 在Blaise Doughan链接中,该示例使用抽象类,而不是接口。

修改:

正如Blaise Doughan在评论中所说,@XmlElementRef更适合这个目的。代码已相应更新。

答案 1 :(得分:1)

你可以写一个转换器。

public class CustomConverter implements Converter {

   public void marshal(Object source, HierarchicalStreamWriter writer,
        MarshallingContext context) {
     // TODO: Get annotation value from object 'source' with name of tag via Reflection.
     // Or add a method to the AnimalConfig interface giving you tag name to put to serialization output.
   }

   public Object unmarshal(HierarchicalStreamReader reader,
        UnmarshallingContext context) {
     // TODO: use reflection to create animal object based on what you xml tag you have at hahd.
     return context.convertAnother(context.currentObject(), SomeAnimalClazz.class);
   }

   public boolean canConvert(Class type) {
     return type.equals(AnimalConfig.class);
   }
 }

存在一个缺点:多态性将要求您使用Java Reflection API并降低性能。

答案 2 :(得分:1)

这很容易。你只需要做正确而不是像我以前的发言者那样。处理注释时,XStream可以分配这些类。

@XStreamAlias("person")
public class PersonConfig {

    private AnimalConfig animalConfig;

    public String toXml() {
        XStream xstream = new XStream();
        xstream.processAnnotations(DogConfig.class);
        xstream.processAnnotations(CatConfig.class);
        return xstream.toXML(this);
    }
}

public interface AnimalConfig {}

@XStreamAlias("dog");
public class DogConfig implements AnimalConfig {}

@XStreamAlias("cat");
public class CatConfig implements AnimalConfig {}

答案 3 :(得分:0)

开箱即用,没有任何注释......

private static interface Test {
    String getName();

    Params getParams();
}

private static interface Params {
}

private static class OneParams implements Params {
    private String oneValue;

    public String getOneValue() {
        return oneValue;
    }

    public void setOneValue(String oneValue) {
        this.oneValue = oneValue;
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append("OneParams [oneValue=");
        builder.append(oneValue);
        builder.append("]");
        return builder.toString();
    }

}

private static class TwoParams implements Params {
    private String twoValue;

    public String getTwoValue() {
        return twoValue;
    }

    public void setTwoValue(String twoValue) {
        this.twoValue = twoValue;
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append("TwoParams [twoValue=");
        builder.append(twoValue);
        builder.append("]");
        return builder.toString();
    }

}

private static class OneTest implements Test {
    private String name;

    private Params params;

    @Override
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public Params getParams() {
        return params;
    }

    public void setParams(Params params) {
        this.params = params;
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append("OneTest [name=");
        builder.append(name);
        builder.append(", params=");
        builder.append(params);
        builder.append("]");
        return builder.toString();
    }

}

----现在反序列化......

    System.out
            .println(ser
                    .deserialize("<XStreamTest_-OneTest><name>OneTest</name><params class=\"XStreamTest$OneParams\"><oneValue>1</oneValue></params></XStreamTest_-OneTest>"));

    System.out
            .println(ser
                    .deserialize("<XStreamTest_-OneTest><name>TwoTest</name><params class=\"XStreamTest$TwoParams\"><twoValue>2</twoValue></params></XStreamTest_-OneTest>"));