JAXB Unmarshalling期间的InstantiationException(抽象基类,带有@XmlSeeAlso具体子类)

时间:2011-09-14 11:34:21

标签: jaxb abstract-class

我遇到了JAXB Unmarshalling错误,如下所示。 foo.bar.Base是一个抽象类,带有@XmlSeeAlso注释,列出了foo.bar.SubBase(这是foo.bar.Base的具体子类)

上述两个类都可以从main / entry类静态访问:com.example.Request

使用包字符串变体viz:

创建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和Ross的指示。我想我应该在这里包含正在处理的模式。 相关模式如下所示:

    <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"/>

那么哪种策略适用于此?

3 个答案:

答案 0 :(得分:8)

@XmlSeeAlso注释用作方便机制,告诉您的JAXB impl还应为引用的类创建元数据。虽然它最常用于指定子类,但它不是配置继承关系的机制。

由于JAXB正在尝试实例化抽象超类(foo.bar.Base)的实例,因此看起来好像您的XML消息没有包含足够的信息来指定要解组的正确子类型。

可以使用xsi:type属性:

来完成此操作

您还可以使用替换组(@XmlElementRef),其中元素名称用于确定适当的子类型:

JAXB实现(例如EclipseLink JAXB (MOXy))也包含用于处理继承的扩展:

如果您想完全忽略继承关系,可以使用@XmlTransient注释:

答案 1 :(得分:3)

您需要在包含对Base的引用的字段上使用XmlElementRef,以告诉JAXB它应该查看子类。 JAXB显然试图实例化你的基类(当然,它无法做到)。

Have a look at XmlElementRef's docs.

答案 2 :(得分:-1)

尝试@XmlSeeAlso

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


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

它有效