Class Cast Exception when trying to unmarshall xml?
Asked Answered
Q

14

59

Trying to get past a class cast exception here:

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

throws this exception:

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

I don't understand this - as the class was generated by the xjc.bat tool - and the classes it generated I have not altered at all - so there should be no casting problems here - the unmarshaller should really be giving me back a class that CAN be cast to FooClass.

Any ideas as to what I am doing wrong?

Quarto answered 1/4, 2009 at 19:57 Comment(0)
O
126

Does FooClass have the XmlRootElement annotation? If not, try:

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

That's based on the Unofficial JAXB Guide.

Oh answered 1/4, 2009 at 20:4 Comment(6)
Why has the JAXB compiler not put an XmlRootElement annotation in my class in the first place - as I cannot find one. Your code works - but I would like to know more - i.e. why does it work?Quarto
Pass - I only investigated far enough to solve the original problem :) I don't really know a lot about JAXB...Oh
it seems that unmarshal only takes one argument. it doesn't work for meHypochlorite
@maoanz: It's overloaded. See jaxb.java.net/nonav/2.2.6/docs/api/javax/xml/bind/…Oh
@JonSkeet: but there is no unmarshal which takes an InputStream and a Class argument.Oxymoron
in my case, it was a variant of this answer : I had copy-pasted the FooClass and forgot to change the @XmlRootElement("foo") in the new class :/Bar
C
22

Use JAXBIntrospector on the JAXBElement to get the schemaObject like >>

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

Refer: when does JAXB unmarshaller.unmarshal returns a JAXBElement<MySchemaObject> or a MySchemaObject?

Cluck answered 21/5, 2012 at 6:2 Comment(3)
And then, what I'm supposed to do with this schemaObject?Estovers
It's been a long time, but if I remember correctly, the object here represents your POJO, use your class instead and unmarshal to an instance of it. You may then use it however you want in your application.Cluck
Refer: #10244179Cluck
M
18

I ran into the same problem today, saw the answers here, did some research and looks to me that the most generic solution is to use JAXBIntrospector. Hence -

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

should be written as

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

Or even better, to make it more generic -

T t = (T) JAXBIntrospector.getValue(unmarshaller.unmarshal(inputStream));
Miscount answered 10/1, 2015 at 11:9 Comment(0)
Q
10

For a fuller explanation read this article. It turns out that your XSD must be properly set up, i.e. there must be some root element encompassing all the other elements.

XJC does try to put @XmlRootElement annotation on a class that we generate from a complex type. The exact condition is somewhat ugly, but the basic idea is that if we can statically guarantee that a complex type won't be used by multiple different tag names, we put @XmlRootElement.

Quarto answered 29/4, 2009 at 16:48 Comment(0)
S
4

We spent too many hours fidgeting with the JAXB factory class to satisfy the unmarshaller. We've learned that using the unmarshaller without calling the JAXB-generated object factory works alright. Hope the sample code redeems someone's frustration:

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);
    }
Sibella answered 11/2, 2011 at 15:54 Comment(0)
P
3

I'd look at the XML file and make sure it is roughly what you expect to see.

I'd also temporarily change the code to:

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

If the first one failes then the class cast is happening inside the unmarshal method, if it succeeds then you can see the actual class that you are getting back and then figure out why it isn't what you expect it to be.

Pestle answered 1/4, 2009 at 23:26 Comment(0)
B
2

Building on the previews answers from colleagues, just in case anybody is still looking for an answer.

I had the issue of having the root element of my scheme being defined as:

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

And therefore I was getting a Cast Exception at:

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
    }

What I did was to change the first line of the try block to:

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

That resolved the problem for me.

Bone answered 2/11, 2011 at 14:40 Comment(0)
S
1

Are you absolutely sure FooClass is the root element of the xml input source you passed it? Unmarshall will return an object of the root element created by xjc.

Scorpio answered 1/4, 2009 at 20:3 Comment(0)
S
1

Sometimes you have a XSD definition with multiple different root elements (for instance XSD defined in WSDL) and in that case the generated classes are missing @XmlRootElement. So as user mbrauh already wrote you have to get the value of JAXBElement. In my case I used:

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

So using generics you can easily avoid double type casting.

Summerwood answered 3/8, 2014 at 12:41 Comment(0)
F
1

If you have access and you can modify the XSD. For me, this issue appends when I generate the XSD from XML with IDEA.

With this xml :

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

IDEA generate an XSD like that and JAXB won't generate an root 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" 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>

BUT, if you modify the XSD in this way (modify your root element "schema" in order to get the xs:complexType inside the tag 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 will generate the root element !

Flori answered 13/11, 2018 at 16:18 Comment(0)
F
0

Specify @XmlRootElement(name="specifyName", namespace="namespace") to transforming object.

Flection answered 9/9, 2011 at 17:19 Comment(0)
G
0

I also encountered the "Javax.xml.bind.JAXBElement cannot be cast to" error and found this very simple solution:

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

Since, apparently, an object of type JAXBElement is returned, you need to typecast its value instead.

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

Gallicism answered 30/10, 2013 at 16:49 Comment(0)
C
0

Try this:

JAXBContext jc = JAXBContext.newInstance(Foo.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
JAXBElement element = (JAXBElement) unmarshaller.unmarshal( new StringReader(xmlString));
Foo foo = (Foo)element;
Clarhe answered 15/7, 2016 at 12:46 Comment(0)
H
0

In my case, I get the error when trying to send a soap petition from the SOAPUI application. I need to set the property 'strip whitespaces' to true to skip this error.

When debug the content received, is a list with the next content:

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

Hope help someone.

Helton answered 6/11, 2018 at 10:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.