JAXB :Class cast exception while trying to unmarshall XML using JAXB - java

I am novice to JAXB , i am trying to sample using JAXB.
trying to dispaly the values in the MenuList.xml
----MenuList.xml-----------
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<menulist xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Category1 name="Development">
<MenuItem1>Projects</MenuItem1>
<MenuItem2>Library</MenuItem2>
<MenuItem3>Library1</MenuItem3>
</Category1>
</menulist>
----------------------------MenuList.xsd-------------------
<?xml version="1.0" encoding="utf-8" ?>
<!--Created with Liquid XML Studio Developer Edition (Trial) 8.0.11.2171 (http://www.liquid-technologies.com)-->
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="menulist">
<xs:complexType>
<xs:sequence>
<xs:element name="Category1">
<xs:complexType>
<xs:attribute name="MenuItem1" type="xs:string" use="required" />
<xs:attribute name="MenuItem2" type="xs:string" use="required" />
<xs:attribute name="MenuItem3" type="xs:string" use="required" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
The uisng the command I run the xsd file and it generated the classes.
MenuList and Object Factory.
AppTest.java
package com.xx.menu;
import java.io.File;
import java.io.IOException;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.UnmarshalException;
import javax.xml.bind.Unmarshaller;
public class TestNew {
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
JAXBContext jc = JAXBContext.newInstance("com.xx.menu"); //Create unmarshaller
Unmarshaller um = jc.createUnmarshaller();
File file = new File ("C:\\sample\\menulist.xml");
JAXBElement element = (JAXBElement)um.unmarshal(file);
Menulist menulist= (Menulist) element.getValue ();
System.out.println("name : "+menulist.getMenu());
}
catch( UnmarshalException ue ) {
ue.printStackTrace();
System.out.println( "Caught UnmarshalException" );
} catch( JAXBException je ) {
je.printStackTrace();
} catch( Exception ioe ) {
ioe.printStackTrace();
}
}
}
Error:
java.lang.ClassCastException: com.xx.menu.Menulist
at com.xx.menu.TestNew.main(TestNew.java:26)
Can you please help me where I am going wrong ...I will be greatly thankful to you.
Thanks

You're overcomplicating things. You don't need to muck about with JAXBElement if the Unmarshaller is giving you the Menulist object directly. The ClassCastExcepotion pretty much tells you what you need to do:
Menulist menulist= (Menulist) um.unmarshal(file);
JAXBElement is only used in certain specific situations, and this isn't one of them.

Could you please add a short description about when JAXBElement is to
be used?
JAXBElement is used by JAXB when a class or property does not contain enough information by itself to indicate what element should be written to XML.
#XmlRootElement
In your example the Menulist class corresponds to the menulist element. Since in the schema that element has an anonymous complex type, one element is associated with the class generated from the corresponding complex type.
#XmlElementDecl
If in your example the menulist element had corresponded to a named complex type, then potentially multiple elements could correspond to the same class generated from that complex type. Instead of annotating the class with #XmlRootElement, one or more #XmlElementDecl annotations would be generated on the ObjectFactory class. This would cause JAXBElement to be unmarshalled.
Handling All Results
If you don't know whether or not a JAXBElement will be returned you can leverage a JAXBIntrospector to do any necessary unwrapping.
JAXBIntrospector ji = jaxbContext.createJAXBIntrospector();
Menulist menulist = (Menulist) ji.getValue(unmarshaller.unmarshal(xml));
For More Information
http://blog.bdoughan.com/2012/07/jaxb-and-root-elements.html

Related

process xml with optional inner tags and values using jaxb

I've got an xml file that looks like this
<console-menu-entry index="2" text="Print Hello World">
<console-menu-entry index="1" text="Print Hello">
print 'Hello'
</console-menu-entry>
<console-menu-entry index="2" text="Print World">
print 'World'
</console-menu-entry>
</console-menu-entry>
Basically node <console-menu-entry> may have either tags inside it or some text value.
How to process it using jaxb? When I do like this it fails with
If a class has #XmlElement property, it cannot have #XmlValue property.
error.
My class looks like this
#XmlRootElement(name="console-menu-entry")
#XmlAccessorType(XmlAccessType.FIELD)
#ToString
public #Data class XmlConsoleMenuEntry {
#XmlAttribute
private String index;
#XmlAttribute
private String text;
#XmlValue
private String value;
#XmlElement(name="console-menu-entry")
private List<XmlConsoleMenuEntry> entries;
}
P.S. Using jaxb is not a requirement so if there is an approach using another library I am open to suggestions.
I would suggest to use JAXB but come from another end. Try to make use of xsd schema. This approach has a number of advantages:
Developing an XSD lets you understand your datamodel more deeply, detect possible flaws and see the data structure more clear.
You can use XSD to generate the parser which will help you to parse your xml (meeting that model) in a few lines of code
You can use XSD to create xml files (all the modern IDEs integrate XSD data in code-assistance mechanisms) so that you will get advice from IDE on which element would fit your datamodel in a particular place, which attribute is requited for a particular element (even which values are suitable for that attrubute) and many other usefule things
Below is the example of xsd schema which will let you generate parser which parses your example (you should only provide appropriate namespace for your xml elements)
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://some.your.schema"
xmlns:tns="http://some.your.schema"
elementFormDefault="qualified">
<xs:complexType name="ConsoleMenuEntry" mixed="true" >
<xs:sequence>
<xs:element ref="tns:console-menu-entry" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="index" type="xs:integer" use="required"/>
<xs:attribute name="text" type="xs:string" use="required"/>
</xs:complexType>
<xs:element name="console-menu-entry" type="tns:ConsoleMenuEntry"/>
</xs:schema>
You now can generate the parser files (Windows example)
"%JAVA_HOME%\bin\xjc" -d ../src -p your.app.generated test.xsd
Where -d ../src specifies the path on hard drive where your parser classes would be located, -p your.app.generated specifies the package for you generated parser classes and test.xsd is the schema file name
Here is the example of test.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<console-menu-entry xmlns="http://some.your.schema" index="1" text="Some new text">
<console-menu-entry index="1" text="some other text">
sdfsdkljf
</console-menu-entry>
<console-menu-entry index="2" text="some other text"/>
</console-menu-entry>
And the code that parses it:
public class Main {
public static void main(String[] args) throws JAXBException {
JAXBContext jc = JAXBContext.newInstance(ObjectFactory.class);
ConsoleMenuEntry rootEntry = ((JAXBElement<ConsoleMenuEntry>) jc.createUnmarshaller().unmarshal(new File("PATH_TO_FILE\\test.xml"))).getValue();
processMenuEntry(rootEntry);
}
private static void processMenuEntry(ConsoleMenuEntry menuEntry) {
System.out.println("Index (attr) = " + menuEntry.getIndex() + ", Text (attr) = '" + menuEntry.getText() + "'");
for (Serializable element : menuEntry.getContent()) {
if (element instanceof JAXBElement) {
processMenuEntry(((JAXBElement<ConsoleMenuEntry>) element).getValue());
} else if (element instanceof String) {
String innerText = element.toString().trim();
if (innerText.length() > 0) {
System.out.println("Inner text: '" + innerText);
}
}
}
}
}

No URI javax.xml.bind.UnmarshalException: unexpected element (uri:"", local:"SearchAndList"). Expected elements are (none)

I am having trouble to unmarshall my data. I got the following error:
ERROR FsceClient - Error in getDataInMatches : unexpected element
(uri:"", local:"SearchAndList"). Expected elements are (none)
requested params:+COUNTRY=US+YR=2016+DIV=Ford+WB=122.0
javax.xml.bind.UnmarshalException: unexpected element (uri:"", local:"SearchAndList"). Expected elements are (none)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.handleEvent(UnmarshallingContext.java:726)
This is my xml file:
<SearchAndList>
<fvd>
+COUNTRY=US+YR=2016+DIV=Ford+WB=122.0
</fvd>
<sol>
<rsi>
<sType>Ss</sType>
<mHave>true</mHave>
<toAr>0</toAr>
<toAr>0</toAr>
<toAr>22</toAr>
</rsi>
<rsi>
<sType>ssa</sType>
<mHave>true</mHave>
<toAr>77</toAr>
</rsi>
</sol>
<sol>
<rsi>
<sType>sve</sType>
<mHave>false</mHave>
<toAr>0</toAr>
<toAr>21</toAr>
</rsi>
</sol>
</SearchAndList>
This is encountered when the XSD schema does not contain element definitions and only contains class definitions (i.e. complex types).
e.g. for this XSD,
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="foo">
<xs:sequence>
<xs:element name="bar" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
The object factory created is like this:
#XmlRegistry
public class ObjectFactory {
public ObjectFactory() {
}
public Foo createFoo() {
return new Foo();
}
}
BUT FOR THIS XSD:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="foo" type="foo" nillable="true"/>
<xs:complexType name="foo">
<xs:sequence>
<xs:element name="bar" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
The ObjectFactory class created by JAXB is:
#XmlRegistry
public class ObjectFactory {
private final static QName _Foo_QNAME = new QName("", "foo");
public ObjectFactory() {
}
public Foo createFoo() {
return new Foo();
}
#XmlElementDecl(namespace = "", name = "foo")
public JAXBElement<Foo> createFoo(Foo value) {
return new JAXBElement<Foo>(_Foo_QNAME, Foo.class, null, value);
}
}
You can see that the JAXBElement wrapper creation method is also added. With the second XSD, the unmarshaller knows what to do when it encounters a tag with name "foo". So if you have an XSD, add "element" definitions as well as the complex types.
----- EDIT----
The sample unmarshaller code:
JAXBContext jaxbContext = JAXBContext.newInstance(ObjectFactory.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
Object result = ((JAXBElement<Object>) jaxbUnmarshaller.unmarshal(stream)).getValue();

XSD:anyType to java Object

I have an xsd as follows:
<xs:complexType name="exampleDataType">
<xs:sequence>
<xs:element name="payload" type="xs:anyType" minOccurs="0"/>
<xs:element name="message" type="tns:message" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
However when I try to get the payload value from java it returns null. Can anyone help me with this?
I have also faced this issue recently, below is the workaround:
XSD:
Java Code:
ClassLoader classLoader = new XmlToObject().getClass().getClassLoader();
File file = new File(classLoader.getResource("myXmlFile.xml").getFile());
JAXBContext jaxbContext = JAXBContext.newInstance(MyPojo.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
MyPojo myPojo = (MyPojo) jaxbUnmarshaller.unmarshal(file);
Object check = myPojo.getCheck();
if (check instanceof Node) {
ElementNSImpl checkElement = (ElementNSImpl) check;
System.out.println("check=" + checkElement.getTextContent());
}

Marshalling a complex type xml element using jaxb

I am running into multiple namespaces while marshalling a complex type Element(contains list of Element in it Example: device see below) using JAXB. Appreciate any help in getting the desired output as mentioned below.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Request xmlns="urn:ietf:params:xml:ns:geopriv:held"
xmlns:ns2="urn:ietf:params:xml:ns:geopriv:held:id"
xmlns:ns3="urn:ietf:params:xml:ns:geopriv:held:vendor" responseTime="10">
<ns2:device xmlns="urn:ietf:params:xml:ns:geopriv:held:id"
xmlns:ns2="urn:ietf:params:xml:ns:geopriv:held">
<uri>http://stackoverflow.com</uri>
</ns2:device>
Here device is a complex type element as defined in the extension schema. I am working with many schema's.
But the desired output without the extra namespaces around device complex type element is like this:
<?xml version="1.0" encoding="utf-8"?>
<Request xmlns="urn:ietf:params:xml:ns:geopriv:held" responseTime="10">
<device xmlns="urn:ietf:params:xml:ns:geopriv:held:id">
<uri>http://stackoverflow.com</uri>
</device>
</Request>
Device Schema:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema targetNamespace="urn:ietf:params:xml:ns:geopriv:held:id"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:id="urn:ietf:params:xml:ns:geopriv:held:id"
elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:element name="device" type="id:deviceIdentity" />
<xs:complexType name="deviceIdentity">
<xs:sequence>
<xs:any xmlns:id="urn:ietf:params:xml:ns:geopriv:held:id"
processContents="strict" minOccurs="0"
maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>
Marshalling Code:
final JAXBElement<String> uri = objectFactory.createUri(uri);
Element elt = XmlMarshaller.getDomElement(uri, String.class);
final Device device = objectFactory.createDevice();
if (elt != null) {
device.getAnies().add(elt);
}
elt = XmlMarshaller.getDomElement(device, Device.class);
Request.getAnies().add(elt);
Element getDomElement(final Object object, final Class<?> clazz) throws JAXBException {
final JAXBContext jaxbContext = JAXBContext.newInstance(clazz);
final Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
final DOMResult res = new DOMResult();
jaxbMarshaller.marshal(object, res);
final Element elt = ((Document) res.getNode()).getDocumentElement();
return (elt);
}

Different parent child namespace prefix expected

I have two xsds from which i have generated jaxb pojos using xjc. And i have generated XMLs using jaxb marshaller with jaxb-impl-2.2.6
For this I have overriden NamespacePrefixMapper as MyNamespacePrefixMapper
Parent.xsd
<xs:schema targetNamespace="parent"
elementFormDefault="qualified"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:Env="Parent"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:child="urn:xsd:child">
<xs:import namespace="urn:xsd:child" schemaLocation="child.xsd"/>
<xs:element name="parent">
<xs:complexType>
<xs:sequence>
<xs:element name="child" type="child:child1"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
child.xsd
<xs:schema xmlns="urn:xsd:child" xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" targetNamespace="urn:xsd:child">
<xs:element name="child" type="child1"/>
<xs:complexType name="child1">
<xs:sequence>
<xs:element name="Id" type="Max20Text"/>
</xs:sequence>
</xs:complexType>
<xs:simpleType name="Max20Text">
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
<xs:maxLength value="20"/>
</xs:restriction>
</xs:simpleType>
XmlMarshallingTest.java
import javax.xml.bind.*;
import javax.xml.stream.XMLStreamException;
import org.junit.Test;
import parent.Parent;
import xsd.child.Child1;
public class XmlMarshallingTest {
#Test
public void testXmlMarshalling() throws JAXBException, XMLStreamException{
Parent envelope = new Parent();
Child1 businessApplicationHeaderV01 = new Child1();
businessApplicationHeaderV01.setId("ABC123");
envelope.setChild(businessApplicationHeaderV01);
JAXBContext context = JAXBContext.newInstance(envelope.getClass());
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper", new MyNamespacePrefixMapper());
marshaller.marshal(envelope, System.out);
}
}
MyNamespacePrefixMapper.java
import com.sun.xml.bind.marshaller.NamespacePrefixMapper;
import com.sun.xml.bind.marshaller.NamespacePrefixMapper;
public class MyNamespacePrefixMapper extends NamespacePrefixMapper {
#Override
public String getPreferredPrefix(String namespaceUri, String suggestion, boolean arg2) {
if("Parent".equals(namespaceUri)) {
return "parentPrefix";
} else if("urn:xsd:child".equals(namespaceUri)) {
return "childPrefix";
}
return "defaultPrefix";
}
}
the generated xml is like
<parentPrefix:parent xmlns:childPrefix="urn:xsd:child" xmlns:parentPrefix="parent">
<parentPrefix:child>
<childPrefix:Id>ABC123</childPrefix:Id>
</parentPrefix:child>
</parentPrefix:parent>
Here, my problem is , I expect the xml to be look like following
<parentPrefix:parent xmlns:childPrefix="urn:xsd:child" xmlns:parentPrefix="parent">
<childPrefix:child>
<childPrefix:Id>ABC123</childPrefix:Id>
</childPrefix:child>
</parentPrefix:parent>
I expect the prefix of child tag to be "childPrefix" but it shows "parentPrefix"
The parent tag is well generated with prefix "parentPrefix"
Environment Description
Maven 3.0.4
Java version: 1.7.0_04
OS : windows 7
Your schema defines the parent element as having a child element named child in the parent schema's own targetNamespace, whose type happens to come from the child namespace. If you want the parent to use the child element that is defined in the child schema (and thus in the urn:xsd:child namespace) then instead of
<xs:element name="child" type="child:child1"/>
you need
<xs:element ref="child:child"/>

Categories