Исключение Instantiation при JAXB Unmarshalling (абстрактный базовый класс, с конкретным подклассом @XmlSeeAlso) - PullRequest
6 голосов
/ 14 сентября 2011

Я сталкиваюсь с ошибкой Unmarshalling JAXB, как показано ниже. Foo.bar.Base - это абстрактный класс с аннотацией @XmlSeeAlso, в которой перечисляется foo.bar.SubBase (который является конкретным подклассом foo.bar.Base)

Оба вышеперечисленных класса статически доступны из основного / начального класса: 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"

Но он не работает во время выполнения во время вызова ниже. Я не могу понять, что здесь не так.

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 and @ 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 ]

8 голосов
/ 14 сентября 2011

Аннотация @XmlSeeAlso используется в качестве удобного механизма, чтобы сообщить вашему JAXB, что метаданные также должны быть созданы для ссылочных классов. Хотя он чаще всего используется для указания подклассов, он не является механизмом для настройки отношений наследования.

Поскольку JAXB пытается создать экземпляр экземпляра абстрактного суперкласса (foo.bar.Base), создается впечатление, что ваше XML-сообщение не содержит достаточно информации, чтобы указать правильный подтип для демаршалирования.

Это можно сделать с помощью атрибута xsi:type:

Вы также можете использовать группы подстановки (@XmlElementRef), где имя элемента используется для определения соответствующего подтипа:

Реализации JAXB (такие как EclipseLink JAXB (MOXy) ) также содержат расширения для обработки наследования:

И если вы хотите вообще игнорировать отношения наследования, вы можете использовать аннотацию @XmlTransient:

3 голосов
/ 14 сентября 2011

Вам нужно использовать XmlElementRef в поле, содержащем ссылку на Base, чтобы сообщить JAXB, что он должен смотреть на подклассы.JAXB явно пытается создать экземпляр вашего базового класса (что, конечно, не может).

Посмотрите документы XmlElementRef.

0 голосов
/ 22 мая 2013

try @ XmlSeeAlso

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


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

работает

...