2011-09-14 53 views
5

我正在運行JAXB Unmarshalling錯誤,如下所示。 foo.bar.Base是一個抽象類,帶有@XmlSeeAlso註釋,其中列出了foo.bar.SubBase(它是foo.bar.Base的具體子類)JAXB Unmarshalling期間的InstantiationException(抽象基類,具有@XmlSeeAlso具體子類)

上述兩個類都是靜態可訪問的從主/入門級:com.example.Request

的JAXBContext而創建是使用包串的變體即:

JAXBContext.newInstance("com.example",...); 

上面創建的JAXBContext正確地列出了所有三類:com.example.Request, foo.bar.Base and foo.bar.SubBase as "classes known to this JAXBContext"

但是在下面的unmarshal調用期間,它在運行時失敗了。我無法弄清楚這裏有什麼問題。

unmarshaller.unmarshal(<some-DOM-Element-Instance>, com.example.Request.class); 

任何指針將不勝感激! 謝謝!

堆棧跟蹤是:

Caused by: javax.xml.bind.UnmarshalException: Unable to create an instance of foo.bar.Base - with linked exception: [java.lang.InstantiationException] 

    at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext.handleEvent(UnmarshallingContext.java:642) 

    at com.sun.xml.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:254) 

    at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext.createInstance(UnmarshallingContext.java:609) 

    at com.sun.xml.bind.v2.runtime.unmarshaller.StructureLoader.startElement(StructureLoader.java:181) 

    at com.sun.xml.bind.v2.runtime.unmarshaller.XsiTypeLoader.startElement(XsiTypeLoader.java:76) 

    at com.sun.xml.bind.v2.runtime.unmarshaller.ProxyLoader.startElement(ProxyLoader.java:55) 

    at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext._startElement(UnmarshallingContext.java:481) 

    at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext.startElement(UnmarshallingContext.java:459) 

    at com.sun.xml.bind.v2.runtime.unmarshaller.InterningXmlVisitor.startElement(InterningXmlVisitor.java:71) 

    at com.sun.xml.bind.v2.runtime.unmarshaller.SAXConnector.startElement(SAXConnector.java:148) 

    at com.sun.xml.bind.unmarshaller.DOMScanner.visit(DOMScanner.java:239) 

    at com.sun.xml.bind.unmarshaller.DOMScanner.visit(DOMScanner.java:276) 

    at com.sun.xml.bind.unmarshaller.DOMScanner.visit(DOMScanner.java:245) 

    at com.sun.xml.bind.unmarshaller.DOMScanner.scan(DOMScanner.java:122) 

    at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:314) 

    at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:293) 

Caused by: java.lang.InstantiationException 

    at sun.reflect.InstantiationExceptionConstructorAccessorImpl.newInstance(InstantiationExceptionConstructorAccessorImpl.java:30) 

    at java.lang.reflect.Constructor.newInstance(Constructor.java:513) 

    at com.sun.xml.bind.v2.ClassFactory.create0(ClassFactory.java:123) 

    at com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.createInstance(ClassBeanInfoImpl.java:261) 

    at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext.createInstance(UnmarshallingContext.java:603) 

    ... 69 more 

編輯@Blaise和@Ross

非常感謝您Blaise和羅斯的三分球。我想我應該在這裏包含正在使用的模式。 相關的模式是這樣的:

<xs:complexType name="Request"> 
        <xs:sequence> 
         <xs:element name="selectedBase" form="unqualified" nillable="true" type="xs:anyType" minOccurs="0"/> 
         <xs:element name="selectedSubBase" form="unqualified" nillable="true" type="ns1:SubBase" minOccurs="0"/> 
        </xs:sequence> 
       </xs:complexType> 


<xs:complexType name="Base"> 
       <xs:sequence> 
        <xs:element name="ID" form="unqualified" nillable="true" type="xs:string" minOccurs="0"/> 
       </xs:sequence> 
      </xs:complexType> 
      <xs:complexType name="SubBase"> 
       <xs:complexContent> 
        <xs:extension base="ns1:Base"> 
         <xs:sequence> 
          <xs:element name="subBaseElement" form="unqualified" nillable="true" type="xs:anyType" minOccurs="0"/> 
         </xs:sequence> 
        </xs:extension> 
       </xs:complexContent> 
      </xs:complexType> 

因此方案不具有替代組定義(所以我想在這裏@XmlElementRef不適,或將它仍然工作嗎?),但使用擴展。有效載荷將是:

<ns:Request> 
     <selectedBase>123</selectedBase> 
     <selectedSubBase> 
      <ID>321</ID> 
      <subBaseElement>123</subBaseElement> 
     </selectedSubBase> 
     </ns:Request> 

因此,在有效載荷發生的歷史元素爲<selectedSubBase>,而不是<selectedBase xsi:type="ns:SubBase"/>

所以其策略將適用於此?

回答

8

@XmlSeeAlso註釋用作一種便利機制來告訴您的JAXB impl還應該爲引用的類創建元數據。雖然它最常用於指定子類,但它不是配置繼承關係的機制。

由於JAXB正在嘗試實例化抽象超類的實例(foo.bar.Base),所以看起來好像您的XML消息沒有包含足夠的信息來指定要被反編組的正確子類型。

也可以使用取代基團(@XmlElementRef),其中,元素名稱被用於確定適當的子類型:

這可以用xsi:type屬性來完成:

JAXB實現(如EclipseLink JAXB (MOXy)),還包含用於處理繼承擴展:

如果你想完全忽略繼承關係,你可以使用@XmlTransient註釋:

+0

要當心,增加原因@XmlElementRef http://stackoverflow.com/questions/790118/jaxb-types-problem – user293756

3

您需要在包含對Base的引用的字段上使用XmlElementRef,以告訴JAXB它應該查看子類。 JAXB顯然是試圖實例化你的基類(當然它不能這麼做)。

Have a look at XmlElementRef's docs.

-1

嘗試@XmlSeeAlso

@XmlSeeAlso({ExchangeFormat.class}) public abstract class MapperJsonXml <T> 


@XmlRootElement(name="ExchangeFormat") public class ExchangeFormat extends MapperJsonXml<ExchangeFormat> 

它的工作原理