2012-07-14 141 views
3

我有這些類:多態性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也有相同的類:

因此,在這兩種情況下,PersonConfig的字段animalConfig已填充。在帶有DogConfig實例的第一個XML中,在帶有CatConfig實例的第二個XML中。

這是可能通過添加一些註釋來使這項工作?

回答

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鏈接中,該示例使用抽象類,而不是接口。

編輯:

正如布萊斯Doughan在其評論說,@XmlElementRef更適合用於這一目的。代碼已相應更新。

+2

+1 - 不過,我會建議使用'@ XmlElementRef'因爲對應於替換組的XML模式的概念,而不是'@ XmlElements'這是用來映射選擇結構:HTTP://博客。 bdoughan.com/2010/11/jaxb-and-inheritance-using-substitution.html – 2012-07-17 17:01:37

+0

是的,你是對的。我不知道'@ XmlElementRef',我讀了你的(很棒的)文章。我會更新我的答案。謝謝 ! – Mordhak 2012-07-18 08:38:17

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和性能下降。

+0

另一個缺點是在'unmarshall'方法內手動完成整個反序列化。如果'CatConfig'或'DogConfig'是簡單的對象,一切都應該沒問題,但如果它們包含嵌套對象或列表等,他將失去xstream自動化反序列化的好處。或者有沒有一種方法可以爲嵌套項目「重新連接」自動化反序列化? – Mordhak 2012-07-17 14:24:47

+0

只要一個派生類 - 一個人只需將它傳遞給上下文並調用'convertAnother'即可。謝謝你的評論。 – 2012-07-17 14:35:06

+0

太棒了,謝謝你的訣竅:) – Mordhak 2012-07-17 14:42:50

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>")); 
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 {}