JAXB 解组期间发生 InstantiationException(抽象基类,带有 @XmlSeeAlso 具体子类)

发布于 2024-12-04 18:55:06 字数 4728 浏览 0 评论 0原文

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

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

JAXBContext 是使用包字符串变量创建的,即:

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

上面创建的 JAXBContext 正确列出了所有三个类:com.example.Request、foo.bar.Base 和foo.bar.SubBase 作为“此 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>

因此,有效负载中出现的元素是 而不是

所以这里适用哪种策略?

I am running into JAXB Unmarshalling error as below.
The foo.bar.Base is an abstract class, with an @XmlSeeAlso annotation, which lists foo.bar.SubBase (which is a concrete subclass of foo.bar.Base)

Both of the above classes are statically reachable from a main/entry class: com.example.Request

The JAXBContext is create using the packages string variant viz:

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

The above created JAXBContext correctly lists all the three classes : com.example.Request, foo.bar.Base and foo.bar.SubBase as "classes known to this JAXBContext"

But it fails at runtime during the unmarshal call below.. I am unable to figure out what is wrong here.

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

Any pointers will be appreciated!
Thanks!

The stacktrace is:

    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

EDIT @Blaise and @Ross

Thank you very much Blaise and Ross for your pointers. I think I should have included the schema that is being worked off, here.
The relevant schema looks like this:

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

So the schema doesn't have substitution group definition (so I guess @XmlElementRef doesn't apply here, or would it still work?), but is using extension. The payload will be :

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

So , the element in the payload occuring is <selectedSubBase> and not <selectedBase xsi:type="ns:SubBase"/>

So which strategy would apply here?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

江心雾 2024-12-11 18:55:06

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

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

这可以通过 xsi:type 属性来完成:

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

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

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

The @XmlSeeAlso annotation is used as a convenience mechanism to tell your JAXB impl that metadata should also be created for the referenced classes. While it is most often used to specify subclasses it is not a mechanism to configure inheritance relationships.

Since JAXB is attempting to instantiate an instance of the abstract super class (foo.bar.Base), it appears as though your XML message does not contain enough information to specify the correct sub-type to be unmarshalled.

This can be done with the xsi:type attribute:

You can also use substitution groups (@XmlElementRef), where the element name is used to determine the appropriate sub-type:

JAXB implementations (such as EclipseLink JAXB (MOXy)), also contain extensions for handling inheritance:

And if you would like to ignore the inheritance relationship altogether you can use the @XmlTransient annotation:

冰雪之触 2024-12-11 18:55:06

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

查看 XmlElementRef 的文档。

You need to be using XmlElementRef on the field containing the reference to Base, to tell JAXB that it should look at subclasses. JAXB is clearly trying to instantiate your base class (which it can't do, of course).

Have a look at XmlElementRef's docs.

人生百味 2024-12-11 18:55:06

尝试 @XmlSeeAlso

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


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

它有效

try @XmlSeeAlso

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


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

it works

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文