2012-06-20 65 views
7

看來JAXB無法讀取它寫入的內容。考慮下面的代碼:JAXB不解組接口列表

interface IFoo { 
    void jump(); 
} 

@XmlRootElement 
class Bar implements IFoo { 
    @XmlElement 
    public String y; 

    public Bar() { 
     y = ""; 
    } 

    public Bar(String y) { 
     this.y = y; 
    } 

    @Override 
    public void jump() { 
     System.out.println(y); 
    } 
} 

@XmlRootElement 
class Baz implements IFoo { 
    @XmlElement 
    public int x; 

    public Baz() { 
     x = 0; 
    } 

    public Baz(int x) { 
     this.x = x; 
    } 

    @Override 
    public void jump() { 
     System.out.println(x); 
    } 
} 

@XmlRootElement 
public class Holder { 
    private List<IFoo> things; 

    public Holder() { 
     things = new ArrayList<>(); 
    } 

    @XmlElementWrapper 
    @XmlAnyElement 
    public List<IFoo> getThings() { 
     return things; 
    } 

    public void addThing(IFoo thing) { 
     things.add(thing); 
    } 
} 

// ... 

try { 
    JAXBContext context = JAXBContext.newInstance(Holder.class, Bar.class, Baz.class); 

    Holder holder = new Holder(); 
    holder.addThing(new Bar("1")); 
    holder.addThing(new Baz(2)); 
    holder.addThing(new Baz(3)); 

    for (IFoo thing : holder.getThings()) { 
     thing.jump(); 
    } 

    StringWriter s = new StringWriter(); 
    context.createMarshaller().marshal(holder, s); 

    String data = s.toString(); 

    System.out.println(data); 

    StringReader t = new StringReader(data); 
    Holder holder2 = (Holder)context.createUnmarshaller().unmarshal(t); 

    for (IFoo thing : holder2.getThings()) { 
     thing.jump(); 
    } 
} 
catch (Exception e) { 
    System.err.println(e.getMessage()); 
} 

這是一個簡單的例子,當然。關鍵是我必須在一個集合中存儲兩個非常不同的實現類Bar和Baz。那麼,我觀察到他們有非常相似的公共接口,所以我創建了一個接口IFoo並使他們兩個來實現它。現在,我想要有工具來保存這個集合並從XML載入。不幸的是,這段代碼並不完全正常工作:集合被保存,但不能被加載!預期的輸出是

1 
2 
3 
some xml 
1 
2 
3 

但不幸的是,實際產量

1 
2 
3 
some xml 
com.sun.org.apache.xerces.internal.dom.ElementNSImpl cannot be cast to testapplication1.IFoo 

很顯然,我需要使用註釋以不同的方式?或者放棄JAXB並尋找其他東西?我可以寫出「XMLNode toXML()」方法,用於所有我不想(de)元帥的類,但是...

+0

檢查的@XmlSeeAlso –

+0

可能重複的使用文檔http://stackoverflow.com/questions/4144296/marshalling -a-list-of-objects-with-jaxb,它也詢問關於接口類型的列表,並且在接受的答案中具有不同的工作方法。 –

回答

8

請嘗試以下方法@XmlAnyElement(lax=true)lax標誌通知JAXB(JSR-222)實現將元素與基於它們的@XmlRootElement@XmlElementDecl註釋的域對象進行匹配。沒有它的內容被視爲DOM節點。

@XmlRootElement 
public class Holder { 
    private List<IFoo> things; 

    public Holder() { 
     things = new ArrayList<>(); 
    } 

    @XmlElementWrapper 
    @XmlAnyElement(lax=true) 
    public List<IFoo> getThings() { 
     return things; 
    } 

    public void addThing(IFoo thing) { 
     things.add(thing); 
    } 
} 

更多信息

+6

它的工作原理。謝謝!但是天哪,所有這些JAXB的東西都像黑魔法一樣,我還沒有找到一個可理解的指南。 –

+1

@Joker_vD - 查看我的Java XML&JSON綁定博客(http://blog.bdoughan.com/)和EclipseLink JAXB(MOXy)用戶指南(http://wiki.eclipse.org/EclipseLink/UserGuide/MOXy) –

+0

與您在以下鏈接的答案中提供的方法相比,此方法的優缺點是什麼? (例如,較早的答案似乎假定該實現集是持有該列表的類已知的。)http://stackoverflow.com/a/4145801/202009 –