cuando hace JAXB unmarshaller.unmarshal devuelve un JAXBElement o un MySchemaObject?


Tengo dos códigos, en dos proyectos java diferentes, haciendo casi lo mismo, (desmarcando la entrada de un servicio web de acuerdo con un archivo xsd).

Pero en un caso debo escribir esto: (Input es un nombre de marcador de posición) (element es OMElement input )

ClassLoader clInput = input.ObjectFactory.class.getClassLoader();
JAXBContext jc = JAXBContext.newInstance("input", clInput);
Unmarshaller unmarshaller = jc.createUnmarshaller();
Input input = (Input)unmarshaller.unmarshal( element.getXMLStreamReader() );

Y en la otra lib debo usar JAXBElement.getValue(), porque es un JAXBElement que se devuelve, y un cast simple (de entrada) simplemente se bloquea:

Input input = (Input)unmarshaller.unmarshal( element.getXMLStreamReader() ).getValue();

¿Sabes lo que conduce a tal diferencia ?

Author: Cheeso, 2012-04-20

5 answers

Si el elemento raíz corresponde únicamente a una clase Java, entonces se devolverá una instancia de esa clase, y si no se devolverá un JAXBElement.

Si desea asegurarse de obtener siempre una instancia del objeto de dominio, puede aprovechar JAXBInstrospector. A continuación se muestra un ejemplo.

Demo

package forum10243679;

import java.io.StringReader;
import javax.xml.bind.*;
import javax.xml.transform.stream.StreamSource;

public class Demo {

    private static final String XML = "<root/>";

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Root.class);
        Unmarshaller unmarshaller = jc.createUnmarshaller();
        JAXBIntrospector jaxbIntrospector = jc.createJAXBIntrospector();

        Object object = unmarshaller.unmarshal(new StringReader(XML));
        System.out.println(object.getClass());
        System.out.println(jaxbIntrospector.getValue(object).getClass());

        Object jaxbElement = unmarshaller.unmarshal(new StreamSource(new StringReader(XML)), Root.class);
        System.out.println(jaxbElement.getClass());
        System.out.println(jaxbIntrospector.getValue(jaxbElement).getClass());
    }

}

Salida

class forum10243679.Root
class forum10243679.Root
class javax.xml.bind.JAXBElement
class forum10243679.Root
 22
Author: Blaise Doughan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-04-20 20:42:26

Depende de la presencia de anotación XmlRootElement en la clase de su elemento raíz.

Si genera sus clases JAXB desde un XSD, se aplican las siguientes reglas:

  • si el tipo del elemento raíz es un tipo anónimo - > Se añade una anotación XmlRootElement a la clase generada
  • si el tipo del elemento raíz es un tipo de nivel superior - > la anotación XmlRootElement se omite de la clase generada

Por eso a menudo elija tipos anónimos para los elementos raíz.

Puede personalizar el nombre de clase de este tipo anónimo con un archivo de personalización. Por ejemplo, crear enlaces.archivo xjc como este:

<jxb:bindings version="1.0"
              xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
              xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <jxb:bindings schemaLocation="yourXsd.xsd" node="/xs:schema">
        <jxb:bindings  node="//xs:element[@name='yourRootElement']">
            <jxb:class name="YourRootElementType"/>
        </jxb:bindings> 
    </jxb:bindings>
</jxb:bindings>
 4
Author: Puce,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-04-20 10:01:15

Necesita agregar a su clase generada por JAXB @XMLRootElement- debe tener un espacio de nombres:

@XmlRootElement(namespace="http://your.namespace.com/", name="yourRootElement")

Eche un vistazo a la pregunta relacionada (hay muchos buenos consejos): Excepción de conversión de clase al intentar desmarcar xml?

 1
Author: Piotr Kochański,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:34:17

Modificando las clases java generadas, no estoy de acuerdo. No permitir todo el formato xsd posible, no estoy de acuerdo.

Gracias a todas sus explicaciones y enlaces, este es el código que he escrito para cuidar de ambos casos, utilizando la Introspección de Anotación. Funciona tanto para la salida como para la entrada, y es (a mi gusto) más genérico:

public class JaxbWrapper {

    private static boolean isXmlRootElement(Class classT){

        Annotation[] annotations = classT.getAnnotations();

        for(Annotation annotation : annotations){
            if(annotation instanceof XmlRootElement){
                return true;
            }
        }       

        return false;
    }

    public static Object unmarshall(Class classObjectFactory, Class classObject, XMLStreamReader xmlStreamReader){

        Package pack = classObjectFactory.getPackage();
        String strPackageName = pack.getName();

        Object returnObject = null;

        try {
            JAXBContext jc = JAXBContext.newInstance(strPackageName, classObjectFactory.getClassLoader());

            Unmarshaller unmarshaller = jc.createUnmarshaller();

            returnObject = unmarshaller.unmarshal( xmlStreamReader );

            boolean bIsRootedElement = isXmlRootElement(classObject);
            if(!bIsRootedElement)
            {
                JAXBElement jaxbElement = (JAXBElement) returnObject;
                returnObject = jaxbElement.getValue();              
            }
        }
        catch (JAXBException e) {
            /*...*/
        }   

        return returnObject;
    }

    private static void writeToXml(Class classObjectFactory, Object obj, XMLStreamWriter xmlStreamWriter){

        Package pack = classObjectFactory.getPackage();
        String strPackageName = pack.getName();

        try {       
            JAXBContext jc = JAXBContext.newInstance(strPackageName, classObjectFactory.getClassLoader());
            Marshaller marshaller = jc.createMarshaller();
            marshaller.marshal(obj, xmlStreamWriter);
        }
        catch(JAXBException e) {
            /*...*/
        }       
    }

    public static String marshall(Class classObjectFactory, Class classObject, Object obj){

        Object objectToMarshall = obj; 

        boolean bIsRootedElement = isXmlRootElement(classObject);
        if(!bIsRootedElement)
        {
            Package pack = classObjectFactory.getPackage();
            String strPackageName = pack.getName();

            String strClassName = classObject.getName();

            QName qName = new QName(strPackageName, strClassName);

            JAXBElement jaxbElement = new JAXBElement(qName, classObject, null, obj);

            objectToMarshall = jaxbElement; 
        }

        StringWriter sw = new StringWriter();
        XMLOutputFactory xmlOutputFactory = XMLOutputFactory.newInstance();
        XMLStreamWriter xmlStreamWriter = null;

        try {
            xmlStreamWriter = xmlOutputFactory.createXMLStreamWriter(sw);

            writeToXml(classObjectFactory, objectToMarshall, xmlStreamWriter);

            xmlStreamWriter.flush();
            xmlStreamWriter.close();
        } 
        catch (XMLStreamException e) {
            /*...*/
        }

        return sw.toString();
    }
}
 0
Author: Stephane Rolland,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-04-20 15:45:05

Tengo el mismo problema. JAXB unmarshaller.unmarshal devuelve un JAXBElement<MyObject> en lugar del MyObject deseado.

Encontré y eliminé @XmlElementDecl. El problema está resuelto.

 0
Author: test7788,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-02 07:39:29