我遇到了JAXB Unmarshalling错误,如下所示。 foo.bar.Base是一个抽象类,带有@XmlSeeAlso注释,列出了foo.bar.SubBase(这是foo.bar.Base的具体子类)
上述两个类都可以从main / entry类静态访问:com.example.Request
使用包字符串变体viz:
创建JAXBContextJAXBContext.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"/>
那么哪种策略适用于此?
答案 0 :(得分:8)
@XmlSeeAlso
注释用作方便机制,告诉您的JAXB impl还应为引用的类创建元数据。虽然它最常用于指定子类,但它不是配置继承关系的机制。
由于JAXB正在尝试实例化抽象超类(foo.bar.Base
)的实例,因此看起来好像您的XML消息没有包含足够的信息来指定要解组的正确子类型。
可以使用xsi:type
属性:
您还可以使用替换组(@XmlElementRef
),其中元素名称用于确定适当的子类型:
JAXB实现(例如EclipseLink JAXB (MOXy))也包含用于处理继承的扩展:
如果您想完全忽略继承关系,可以使用@XmlTransient
注释:
答案 1 :(得分:3)
您需要在包含对Base的引用的字段上使用XmlElementRef,以告诉JAXB它应该查看子类。 JAXB显然试图实例化你的基类(当然,它无法做到)。
答案 2 :(得分:-1)
@XmlSeeAlso({ExchangeFormat.class}) public abstract class MapperJsonXml <T>
@XmlRootElement(name="ExchangeFormat") public class ExchangeFormat extends MapperJsonXml<ExchangeFormat>
它有效