2011-09-14 16 views
5

Me encuentro con JAXB Unmarshalling error como a continuación. El foo.bar.Base es una clase abstracta, con una anotación @XmlSeeAlso, que enumera foo.bar.SubBase (que es una subclase concreta de foo.bar.Base)InstantiationException durante JAXB Unmarshalling (clase base abstracta, con @XmlSeeAlso subclase de concreto)

Ambos de las clases anteriores son estáticamente alcanzable de una clase principal/entrada: com.example.Request

el JAXBContext es crear paquetes utilizando la variante de cadena a saber:

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

el JAXBContext creado anterior aparece correctamente todas las tres clases: com.example.Request, foo.bar.Base and foo.bar.SubBase as "classes known to this JAXBContext"

Pero falla en tiempo de ejecución durante la llamada unmarshal a continuación ... No puedo entender qué está mal aquí.

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

¡Todos los indicadores serán apreciados! Gracias!

El StackTrace es:

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 

EDITAR @Blaise y @Ross

Muchas gracias Blaise y Ross para sus punteros. Creo que debería haber incluido el esquema que se está trabajando aquí. El esquema correspondiente se parece a esto:

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

Así que el esquema no tiene definición de grupo de sustitución (así que supongo @XmlElementRef no se aplica aquí, o habría que siguen trabajando?), Pero está utilizando la extensión. La carga útil será:

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

Por lo tanto, el elemento de la carga útil es occuring <selectedSubBase> y no <selectedBase xsi:type="ns:SubBase"/>

Entonces, ¿qué estrategia se aplicaría aquí?

Respuesta

8

La anotación @XmlSeeAlso se utiliza como mecanismo de conveniencia para decirle a su JAXB impl que también se deben crear metadatos para las clases a las que se hace referencia. Si bien se usa con mayor frecuencia para especificar subclases, no es un mecanismo para configurar las relaciones de herencia.

Como JAXB está intentando crear una instancia de una superclase abstracta (foo.bar.Base), parece que su mensaje XML no contiene suficiente información para especificar el subtipo correcto que se desregulará.

Esto se puede hacer con el atributo xsi:type:

También puede utilizar grupos de sustitución (@XmlElementRef), donde se utiliza el nombre del elemento para determinar la sub-tipo apropiado:

implementaciones JAXB (como EclipseLink JAXB (MOXy)), también contienen extensiones para el manejo de la herencia:

Y si le gustaría hacer caso omiso de la relación de herencia por completo se puede utilizar la anotación @XmlTransient:

+0

Atención, añadiendo causa @XmlElementRef http://stackoverflow.com/questions/790118/jaxb-types-problem – user293756

3

Debe usar XmlElementRef en el campo que contiene la referencia a Base, para decirle a JAXB que debe mirar las subclases. JAXB intenta claramente crear una instancia de tu clase base (lo que no puede hacer, por supuesto).

Have a look at XmlElementRef's docs.

-1

tratar @XmlSeeAlso

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


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

que funciona

Cuestiones relacionadas