2012-08-15 28 views
3

我有一個父子關係,子類:Foo是不可變的,並且沒有定義默認的無參數構造函數。父級:Bar通過接口引用兒童:IFoo。我已經定義了一個適配器來解決構造函數問題,但現在又碰到了另一個問題,JAXB抱怨Foo類在這個上下文中是不知道的。獲取XmlJavaTypeAdapter和接口播放很好

如果我試圖通過引導我的JAXBContextFoo.class來解決這個問題,那麼我會收到缺少構造函數的錯誤。

請注意,我試圖遵循3.2.1 of the Unofficial JAXB Guide中描述的接口映射方法。

我需要採取不同的接口映射方法來解決這個問題嗎?我懷疑使用XmlRootElement標記每個接口實現意味着我的適配器代碼沒有運行(如Blaise Doughan here所述)。這讓我想知道這兩種方法是否固有地不兼容,並且我需要使用其中描述的其他接口映射技術之一。

public interface IFoo { 
    String getName(); 
    int getAge(); 
} 

@XmlJavaTypeAdapter(FooAdapter.class) 
@XmlRootElement 
public class Foo implements IFoo { 
    private final String name; 
    private final int age; 

    public Foo(String name, int age) { 
    this.name = name; 
    this.age = age; 
    } 

    public String getName() { return name; } 
    public int getAge() { return age; } 
} 

public class FooAdapter extends XmlAdapter<AdaptedFoo, Foo> { 
    @Override 
    public Foo unmarshal(AdaptedFoo af) throws Exception { 
    return new Foo(af.getName(), af.getAge()); 
    } 

    @Override 
    public AdaptedFoo marshal(Foo foo) throws Exception { 
    AdaptedFoo ret = new AdaptedFoo(); 
    ret.setName(foo.getName()); 
    ret.setAge(foo.getAge()); 
    return ret; 
    } 
} 

public class AdaptedFoo { 
    private String name; 
    private int age; 

    public AdaptedFoo() {} 

    @XmlAttribute 
    public String getName() { return name; } 
    public void setName(String name) { this.name = name; } 

    @XmlAttribute 
    public int getAge() { return age; } 
    public void setAge(int age) { this.age = age; } 
} 

@XmlRootElement 
@XmlAccessorType(XmlAccessType.FIELD) 
public class Bar { 
    @XmlAnyElement 
    private IFoo foo; 
    private int baz; 

    public Bar() {} 

    public IFoo getFoo() { return foo; } 
    public void setFoo(IFoo foo) { this.foo = foo; } 

    public int getBaz() { return baz; } 
    public void setBaz(int baz) { this.baz = baz; } 
} 

public class Marshal { 
    public static void main(String[] args) { 
    Foo foo = new Foo("Adam", 34); 
    Bar bar = new Bar(); 
    bar.setFoo(foo); 
    bar.setBaz(10); 

    try { 
     JAXBContext jaxbContext = JAXBContext.newInstance(Bar.class, AdaptedFoo.class); 
     Marshaller jaxbMarshaller = jaxbContext.createMarshaller(); 

     // output pretty printed 
     jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); 

     jaxbMarshaller.marshal(bar, System.out); 
    } catch (JAXBException e) { 
     e.printStackTrace(); 
    } 
    } 
} 

堆棧跟蹤

$ java Marshal 
javax.xml.bind.MarshalException 
- with linked exception: 
[com.sun.istack.internal.SAXException2: class Foo nor any of its super class is known to this context. 
javax.xml.bind.JAXBException: class Foo nor any of its super class is known to this context.] 
     at com.sun.xml.internal.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:311) 
     at com.sun.xml.internal.bind.v2.runtime.MarshallerImpl.marshal(MarshallerImpl.java:236) 
     at javax.xml.bind.helpers.AbstractMarshallerImpl.marshal(AbstractMarshallerImpl.java:95) 
     at Marshal.main(Marshal.java:20) 
Caused by: com.sun.istack.internal.SAXException2: class Foo nor any of its super class is known to this context. 
javax.xml.bind.JAXBException: class Foo nor any of its super class is known to this context. 
     at com.sun.xml.internal.bind.v2.runtime.XMLSerializer.reportError(XMLSerializer.java:235) 
     at com.sun.xml.internal.bind.v2.runtime.XMLSerializer.reportError(XMLSerializer.java:250) 
     at com.sun.xml.internal.bind.v2.runtime.property.SingleReferenceNodeProperty.serializeBody(SingleReferenceNodePr 
operty.java:102) 
     at com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.java:341) 
     at com.sun.xml.internal.bind.v2.runtime.XMLSerializer.childAsSoleContent(XMLSerializer.java:582) 
     at com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl.serializeRoot(ClassBeanInfoImpl.java:323) 
     at com.sun.xml.internal.bind.v2.runtime.XMLSerializer.childAsRoot(XMLSerializer.java:483) 
     at com.sun.xml.internal.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:308) 
     ... 3 more 
Caused by: javax.xml.bind.JAXBException: class Foo nor any of its super class is known to this context. 
     at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.getBeanInfo(JAXBContextImpl.java:573) 
     at com.sun.xml.internal.bind.v2.runtime.property.SingleReferenceNodeProperty.serializeBody(SingleReferenceNodePr 
operty.java:94) 
     ... 8 more 

回答

4

如果使用和@XmlElement註解放在foo屬性並指定實現類型,那麼你的使用情況應該工作。

@XmlElement(type=Foo.class) 
    private IFoo foo; 

酒吧

下面是你的Bar

@XmlRootElement 
@XmlAccessorType(XmlAccessType.FIELD) 
public class Bar { 
    @XmlElement(type=Foo.class) 
    private IFoo foo; 
    private int baz; 

    public Bar() {} 

    public IFoo getFoo() { return foo; } 
    public void setFoo(IFoo foo) { this.foo = foo; } 

    public int getBaz() { return baz; } 
    public void setBaz(int baz) { this.baz = baz; } 
} 

更新版本的更多信息

+0

感謝您的回答,但看起來像我很快就接受了它。我得到了相同的錯誤(與Foo沒有無參數ctor有關) - 就好像XmlJavaTypeAdapter註釋被忽略一樣。 – Adamski 2012-08-16 07:54:58

相關問題