quand est-ce que JAXB est unmarshaller.unmarshal renvoie un JAXBElement ou un MySchemaObject?

j'ai deux codes, dans deux projets java différents, faisant presque la même chose (démonter l'entrée d'un service web selon un fichier xsd).

Mais, dans un cas, je devrais écrire ceci: (Entrée est un espace réservé de nom) ( élément est OMElement d'entrée )

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

et dans l'autre lib je dois utiliser JAXBElement.getValue (), parce que C'est un JAXBElement qui est retourné, et qu'un cast simple (Input) s'écrase simplement:

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

savez-vous ce qui mène à une telle différence ?

24
demandé sur Cheeso 2012-04-20 13:36:18

5 réponses

Si l'élément racine unique correspond à une classe Java alors une instance de cette classe sera retourné, et si ce n'est un JAXBElement sera retourné.

si vous voulez vous assurer que vous obtenez toujours une instance de l'objet domaine, vous pouvez utiliser le JAXBInstrospector . Ci-dessous est un exemple.

Démo

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());
    }

}

Sortie

class forum10243679.Root
class forum10243679.Root
class javax.xml.bind.JAXBElement
class forum10243679.Root
22
répondu Blaise Doughan 2012-04-20 20:42:26

cela dépend de la présence de xmlrootelement annotation sur la classe de votre élément racine.

si vous générez vos classes JAXB à partir D'un XSD, les règles suivantes s'appliquent:

  • si le type de l'élément racine est un type anonyme - > xmlrootelement l'annotation est ajoutée à la classe générée
  • si le type de l'élément racine est un type de niveau supérieur - > xmlrootelement annotation est omis de la classe générée

pour cette raison, je choisis souvent des types anonymes pour les éléments racine.

vous pouvez personnaliser le nom de classe de ce type anonyme avec un fichier de personnalisation. Par exemple: créer une reliure.fichier xjc comme ceci:

<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
répondu Puce 2012-04-20 10:01:15

vous devez ajouter à votre classe générée par JAXB @XMLRootElement - il devrait avoir l'espace de nom:

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

jetez un coup d'oeil à la question connexe (il y a beaucoup de bons conseils): Classe Cast Exception lors de l'essai de unmarshall xml?

1
répondu Piotr Kochański 2017-05-23 12:34:17

Modifier les classes java générées, Je ne suis pas d'accord. Ne pas autoriser tous les formats xsd possibles, Je ne suis pas d'accord.

Merci pour toutes vos explications d'un des liens, c'est le code que j'ai écrit afin de prendre soin de ces deux cas, l'utilisation de l'Annotation à l'Introspection. Il fonctionne pour la sortie ainsi que l'entrée, et est (à mon goût) plus générique:

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
répondu Stephane Rolland 2012-04-20 15:45:05

j'ai le même problème. JAXB unmarshaller.unmarshal retourne un JAXBElement<MyObject> au lieu du MyObject désiré .

j'ai trouvé et enlevé @XmlElementDecl . Le problème est résolu.

0
répondu test7788 2018-02-02 07:39:29