web-dev-qa-db-fra.com

Classe Cast Exception lorsque vous essayez d'unmarshall xml?

Essayer de dépasser une exception de casting de classe ici:

FooClass fooClass = (FooClass ) unmarshaller.unmarshal(inputStream);

jette cette exception:

Java.lang.ClassCastException: javax.xml.bind.JAXBElement

Je ne comprends pas cela - car la classe a été générée par l'outil xjc.bat - et les classes qu'elle a générées ne sont pas modifiées du tout - il ne devrait donc y avoir aucun problème de casting ici - le spectateur doit vraiment me rendre une classe qui peut être jeté sur FooClass.

Des idées sur ce que je fais mal?

45
Vidar

Est-ce que FooClass a l'annotation XmlRootElement? Si non, essayez:

Source source = new StreamSource(inputStream);
JAXBElement<FooClass> root = unmarshaller.unmarshal(source, FooClass.class);
FooClass foo = root.getValue();

Ceci est basé sur le Guide JAXB non officiel .

103
Jon Skeet

Utilisez JAXBIntrospector sur le JAXBElement pour obtenir le schemaObject comme >>

JAXBContext jaxbContext = JAXBContext.newInstance(Class.forName(className));
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
Object schemaObject = JAXBIntrospector.getValue(unmarshaller.unmarshal(new ByteArrayInputStream(xmlString.getBytes())));

Voir: quand JAXB unmarshaller.unmarshal renvoie-t-il un JAXBElement <MySchemaObject> ou un MySchemaObject?

14
Rahul Thakur

J'ai rencontré le même problème aujourd'hui, j'ai vu les réponses ici, j'ai fait quelques recherches et je pense que la solution la plus générique est d'utiliser JAXBIntrospector . Par conséquent -

FooClass fooClass = (FooClass ) unmarshaller.unmarshal(inputStream);

devrait être écrit comme 

FooClass fooClass = (FooClass) JAXBIntrospector.getValue(unmarshaller.unmarshal(inputStream));

Ou même mieux, pour le rendre plus générique -

T t = (T) JAXBIntrospector.getValue(unmarshaller.unmarshal(inputStream));
14
Gaurav B

Pour une explication plus complète, lisez cet article . Il s’avère que votre XSD doit être correctement configuré, c’est-à-dire qu’il doit exister un élément racine englobant tous les autres éléments.

XJC essaie de placer l'annotation @XmlRootElement sur une classe générée à partir d'un type complexe. La condition exacte est quelque peu moche, mais l'idée de base est que si nous pouvons garantir de manière statique qu'un type complexe ne sera pas utilisé par plusieurs noms de balises différents, nous mettons @XmlRootElement.

9
Vidar

Nous avons passé trop d’heures à jouer avec la classe d’usine JAXB pour satisfaire l’unmarshaller. Nous avons appris que l'utilisation de l'unmarshaller sans l'appel de la fabrique d'objets générée par JAXB fonctionne correctement. J'espère que l'exemple de code rachète la frustration de quelqu'un:

System.out.println("Processing generic-type unmarshaller: ");
MessageClass mcObject = unmarshalXml(MessageClass.class, msgQryStreamSource,
    NAMESPACE + "." + "MessageClass");

public static <T> T unmarshalXml(Class<T> clazz, StreamSource queryResults,
    String contextNamespace)
    {
        T resultObject = null;
        try {
            //Create instance of the JAXBContext from the class-name
            JAXBContext jc;
            jc = JAXBContext.newInstance(Class.forName(clazz.getName()));
            Unmarshaller u = jc.createUnmarshaller();
            resultObject = clazz.cast(u.unmarshal(queryResults));
            }
              //Put your own error-handling here.
        catch(JAXBException e)
        {
            e.printStackTrace();
        }
        catch (ClassCastException e)
        {
            e.printStackTrace();
        }
        catch (ClassNotFoundException e)
        {
            e.printStackTrace();
        }
        return clazz.cast(resultObject);
    }
3
MAbraham1

Je regarderais le fichier XML et m'assurerais que c'est à peu près ce que vous vous attendez à voir.

Je voudrais aussi temporairement changer le code pour:

Object o = unmarshaller.unmarshal(inputStream);
System.out.println(o.getClass());

Si la première échoue, la conversion de classe a lieu dans la méthode unmarshal. Si elle réussit, vous pouvez voir la classe que vous récupérez, puis déterminer pourquoi elle n’est pas ce que vous espérez.

3
TofuBeer

S'appuyant sur les réponses fournies par les collègues, au cas où quelqu'un chercherait toujours une réponse.

J'ai eu le problème d'avoir l'élément racine de mon schéma étant défini comme:

<schema>
  <element name="foo" type="bar" />
  <complexType name="bar" />
</schema>

Et donc je recevais une exception de casting à:

try {            
        javax.xml.bind.JAXBContext jaxbCtx = javax.xml.bind.JAXBContext.newInstance(mobilityConfigType.getClass().getPackage().getName());            
        javax.xml.bind.Unmarshaller unmarshaller = jaxbCtx.createUnmarshaller();
        File f = FileUtil.toFile(this.getPrimaryFile());            
        mobilityConfigType = (MobilityModelConfigType)unmarshaller.unmarshal(FileUtil.toFile(this.getPrimaryFile()));
    } catch (javax.xml.bind.JAXBException ex) {            
        Java.util.logging.Logger.getLogger("global").log(Java.util.logging.Level.SEVERE, null, ex); //NOI18N
    }

Ce que j'ai fait était de changer la première ligne du bloc try en:

javax.xml.bind.JAXBContext jaxbCtx = javax.xml.bind.JAXBContext.newInstance(mobilityConfigType.getClass().getName());

Cela a résolu le problème pour moi.

2

Êtes-vous absolument certain que FooClass est l'élément racine de la source d'entrée XML que vous avez transmise? Unmarshall retournera un objet de l'élément racine créé par xjc.

1
Greg Noe

Parfois, vous avez une définition XSD avec plusieurs éléments racine différents (par exemple, XSD défini dans WSDL) et dans ce cas, les classes générées sont manquantes @XmlRootElement. Donc, comme l'utilisateur mbrauh l'a déjà écrit, vous devez obtenir la valeur de JAXBElement. Dans mon cas j'ai utilisé:

FooClass request = ((JAXBElement< FooClass >) marshaller.unmarshal(new StreamSource(classPathResource.getInputStream()))).getValue();

Donc, en utilisant des génériques, vous pouvez facilement éviter le double typage.

1
Marek Branicky

J'ai également rencontré l'erreur "Javax.xml.bind.JAXBElement ne peut pas être converti en" et j'ai trouvé cette solution très simple:

FooClass fooClass = (FooClass) ((JAXBElement) u.unmarshal(new File("xml/foo.xml")) ).getValue();

Comme, apparemment, un objet de type JAXBElement est renvoyé, vous devez plutôt transtyper sa valeur.

Source: https://forums.Oracle.com/thread/1625944

0
mbrauh

Dans mon cas, j'obtiens l'erreur en essayant d'envoyer une pétition de savon depuis l'application SOAPUI. Je dois définir la propriété 'strip whitespaces' sur true pour ignorer cette erreur.

Lorsque déboguer le contenu reçu, est une liste avec le contenu suivant:

[0] = "\n"
[1] = JAXBElement
[2] = "\n"

J'espère aider quelqu'un.

0

Spécifiez @XmlRootElement (nom = "nomDe" ", espace de noms =" espace de nom ") pour transformer l'objet.

0
user752749

Essaye ça: 

JAXBContext jc = JAXBContext.newInstance(Foo.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
JAXBElement element = (JAXBElement) unmarshaller.unmarshal( new StringReader(xmlString));
Foo foo = (Foo)element;
0
LazyCoder

Si vous y avez accès et que vous pouvez modifier le fichier XSD . Pour moi, ce problème s'ajoute lorsque je génère le fichier XSD à partir de XML avec IDEA.

Avec ce xml:

<?xml version="1.0"?>
<schema>
  <element name="foo" type="bar" />
  <complexType name="bar" />
</schema>

IDEA génère un tel fichier XSD et JAXB ne génère pas d’élément racine: 

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="schema" type="schemaType"/>
  <xs:complexType name="schemaType">
    <xs:sequence>
      <xs:element type="elementType" name="element"/>
      <xs:element type="complexTypeType" name="complexType"/>
    </xs:sequence>
  </xs:complexType>
  <xs:complexType name="elementType">
    <xs:simpleContent>
      <xs:extension base="xs:string">
        <xs:attribute type="xs:string" name="name"/>
        <xs:attribute type="xs:string" name="type"/>
      </xs:extension>
    </xs:simpleContent>
  </xs:complexType>
  <xs:complexType name="complexTypeType">
    <xs:simpleContent>
      <xs:extension base="xs:string">
        <xs:attribute type="xs:string" name="name"/>
      </xs:extension>
    </xs:simpleContent>
  </xs:complexType>
</xs:schema>

MAIS, si vous modifiez le XSD de cette manière (modifiez votre élément racine "schéma" afin d’obtenir le Xs: complexType à l’intérieur de la balise xs: element): 

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="schema">
    <xs:complexType>
      <xs:sequence>
        <xs:element type="elementType" name="element"/>
        <xs:element type="complexTypeType" name="complexType"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  <xs:complexType name="schemaType">
    <xs:sequence>
      <xs:element type="elementType" name="element"/>
      <xs:element type="complexTypeType" name="complexType"/>
    </xs:sequence>
  </xs:complexType>
  <xs:complexType name="elementType">
    <xs:simpleContent>
      <xs:extension base="xs:string">
        <xs:attribute type="xs:string" name="name"/>
        <xs:attribute type="xs:string" name="type"/>
      </xs:extension>
    </xs:simpleContent>
  </xs:complexType>
  <xs:complexType name="complexTypeType">
    <xs:simpleContent>
      <xs:extension base="xs:string">
        <xs:attribute type="xs:string" name="name"/>
      </xs:extension>
    </xs:simpleContent>
  </xs:complexType>
</xs:schema>

JAXB va générer l'élément racine!

0
Antho