xml string to java object using jaxb - java

I am getting an 832edi file with namespaces as xml string, i need to extract elements from this xml string. So i have generated jaxb classes based on 832edi file. When i am trying to store the contents of the xml string i am getting the following exception
javax.xml.bind.JAXBElement cannot be cast to org.bam.jaxb.Transaction834
I am using the following code to parse the xml string
JAXBContext jaxbContext = JAXBContext.newInstance("org.bam.jaxb");
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
StringReader reader = new StringReader(im.getPayload());
Transaction834 edi = (Transaction834) unmarshaller.unmarshal(reader);
List<Loop2000> loop2000=edi.getLoop2000();
System.out.println(loop2000.get(10));
where im.getPayload() will return an xml string . Here is the fragment of the xml.
<?xml version = '1.0' encoding = 'UTF-8'?><Transaction-834 xmlns:zcha="http://www.edifecs.com/xdata/200" XDataVersion="2.0" Standard="X12" Version="V5010" GUID="{C7846049-8C91-4E59-B0BA-4B24CEE69FBB}" CreatedBy="XEngine_4016" CreatedDate="2013-09-05T12:36:12" xmlns="http://www.edifecs.com/xdata/200"><zcha:Segment-ISA><zcha:Element-I01 Offset="4" Size="2">00</zcha:Element-I01><zcha:Element-I02 Offset="7" Size="10">Authorizat</zcha:Element-I02><zcha:Element-I03 Offset="18" Size="2">00</zcha:Element-I03><zcha:Element-I04 Offset="21" Size="10">Security I</zcha:Element-I04><zcha:Element-I05 Offset="32" Size="2">01</zcha:Element-I05><zcha:Element-I06 Offset="35" Size="15">Interchange Sen</zcha:Element-I06><zcha:Element-I05_1 Offset="51" Size="2">01</zcha:Element-I05_1><zcha:Element-I07 Offset="54" Size="15">Interchange Rec</zcha:Element-I07><zcha:Element-I08 Offset="70" Size="6">130905</zcha:Element-I08><zcha:Element-I09 Offset="77" Size="4">1236</zcha:Element-I09><zcha:Element-I65 Offset="82" Size="1">*</zcha:Element-I65><zcha:Element-I11 Offset="84" Size="5">00501</zcha:Element-I11><zcha:Element-I12 Offset="90" Size="9">000000001</zcha:Element-I12><zcha:Element-I13 Offset="100" Size="1">0</zcha:Element-I13><zcha:Element-I14 Offset="102" Size="1">I</zcha:Element-I14><zcha:Element-I15 Offset="104" Size="1">\</zcha:Element-I15></zcha:Segment-ISA><zcha:Segment-GS><zcha:Element-479 Offset="110" Size="2">BE</zcha:Element-479><zcha:Element-142 Offset="113" Size="15">Application Sen</zcha:Element-142><zcha:Element-124 Offset="129" Size="15">Application Rec</zcha:Element-124><zcha:Element-373 Offset="145" Size="8">20130905</zcha:Element-373><zcha:Element-337 Offset="154" Size="6">123602</zcha:Element-337><zcha:Element-28 Offset="161" Size="1">1</zcha:Element-28><zcha:Element-455 Offset="163" Size="1">T</zcha:Element-455><zcha:Element-480 Offset="165" Size="6">005010</zcha:Element-480></zcha:Segment-GS><zcha:Segment-ST><zcha:Element-143 Offset="176" Size="3">834</zcha:Element-143><zcha:Element-329 Offset="180" Size="4">0001</zcha:Element-329></zcha:Segment-ST><zcha:Segment-BGN><zcha:Element-353 Offset="190" Size="2">00</zcha:Element-353><zcha:Element-127 Offset="193" Size="24">Reference Identification</zcha:Element-127><zcha:Element-373 Offset="218" Size="8">20130905</zcha:Element-373></zcha:Segment-BGN><zcha:Loop-1000><zcha:Segment-N1><zcha:Element-98 Offset="231" Size="2">00</zcha:Element-98><zcha:Element-93 Offset="234" Size="4">Name</zcha:Element-93></zcha:Segment-N1><zcha:Segment-N4/></zcha:Loop-1000><zcha:Segment-SE><zcha:Element-96 Offset="243" Size="1">4</zcha:Element-96><zcha:Element-329 Offset="245" Size="4">0001</zcha:Element-329></zcha:Segment-SE><zcha:Segment-GE><zcha:Element-97 Offset="254" Size="1">1</zcha:Element-97><zcha:Element-28 Offset="256" Size="1">1</zcha:Element-28></zcha:Segment-GE><zcha:Segment-IEA><zcha:Element-I16 Offset="263" Size="1">1</zcha:Element-I16><zcha:Element-I12 Offset="265" Size="9">000000001</zcha:Element-I12></zcha:Segment-IEA></Transaction-834>
Here Transaction834 is the root element of the xsd.Please could you suggest me where am i doing the mistake ?
thanks for your patience.

Most likely the class Transaction834 doesn't specify the XmlRootElement annotation (probably because it's a top-level type rather than an anonymous type).
In this case you have to use something like:
JAXBElement<Transaction834> ediElement = unmarshaller.unmarshal(new StreamSource(reader), Transaction834.class);
Transaction834 edi = ediElement.getValue();

When you aren't sure whether the result returned from JAXB will be you can use JAXBInstropector to do any unwrapping of the JAXBElement if necessary.
JAXBContext jaxbContext = JAXBContext.newInstance("org.bam.jaxb");
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
StringReader reader = new StringReader(im.getPayload());
Transaction834 edi = (Transaction834) JAXBIntrospector.getValue(unmarshaller.unmarshal(reader));
For More Information
http://blog.bdoughan.com/2012/07/jaxb-and-root-elements.html

Related

Unmarshal Xml components to Java Object using JAXB

I've done marshalling java object to XML elements.
Now I face a difficulty to unmarshal XML file to java object using JAXB.
Is it similar as marshalling java object to XML?
Below is the XML file that I got from the external API.
<ShoppingMall>
<ProductList>
<product_info>
<group_nm>electronic device</group_nm>
<group_code>e001</group_code>
<product_nm>computer</product_nm>
<price>30000</price>
</product_info>
<product_info>
<group_nm>living</group_nm>
<group_code>lv002</group_code>
<product_nm>bed</product_nm>
<price>140000</price>
</product_info>
<product_info>
<group_nm>Food</group_nm>
<group_code>f001</group_code>
<product_nm>pasta</product_nm>
<price>10</price>
</product_info>
</ProductList>
</ShoppingMall>
To exchange XML element to java object, what should I do with JAXB?
firstly create three java classes for,
ShoppingMall (ProductList is a xml element in this class)
ProductList (product_info is a xml element in this class)
product_info (group_nm, group_code, product_nm and price are xml elements in this class)
then try with this,
JAXBContext jaxbContext = JAXBContext.newInstance(ShoppingMall.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
ShoppingMall shoppingMall = (ShoppingMall) jaxbUnmarshaller.unmarshal( new File("your_xml_file.xml") );
I suppose you want to unmarshal to ShoppingMall class. So, you might write something like this.
ShoppingMall shoppingMall = getShoppignMallByUnmarshal(your_xml);
public static getShoppignMallByUnmarshal(
String xml) throws JAXBException
{
JAXBContext jaxbContext = JAXBContext.newInstance(package.path.of.ShoppingClass.ObjectFactory.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
return ((JAXBElement<ShoppingMall>) jaxbUnmarshaller.unmarshal(new StringReader(xml)))
.getValue();
}

How to fix this Unmarshal Exception with JAXB that arose on fixing XXE vulnerabilites?

The format of the XML Message we supposed to process is so:
<?xml version="1.0" encoding="UTF-8"?>
<ns0:MessageType xmlns:ns0="http://www.path.to/some/schema.xsd">
<ns0:NonRelevantBody>
....
</ns0:NonRelevantBody>
</ns0:MessageType>
Exception recieved:
javax.xml.bind.UnmarshalException: unexpected element (uri:"", local:"ns0:MessageType"). Expected elements are <{http://www.path.to/some/schema.xsd}MessageType>
The above exception occurs in com.xmlprocessor.MessageParser class.
The code in the said class used to be so (and had been working for ages):
StringReader stringReader = new StringReader(xmlMessageAsString);
JAXBContext context = new JAXBContext.newInstance(MessageObjectFactory.class);
Unmarshaller unmarshalr = context.createUnmarshaller();
this.messageTypeContent = (MessageTypeContent) unmarshalr.unmarshal(stringReader);
Turns out this can give you a bad case of XXE. So we tried a number of very similar things DocumentBuilder, SAXParser etc. for disabling External Entities, Doctype Declaration and such things. All gave us the very same exception stated above. Anyways, here's the change with SAXParser:
StringReader stringReader = new StringReader(xmlMessageAsString);
SAXParserFactory spf = SAXParserFactory.newInstance();
spf.setFeature("http://xml.org/sax/features/external-general-entities", false);
spf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
spf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
Source xmlSource = new SAXSource(spf.newSAXParser().getXMLReader(), new InputSource(stringReader));
JAXBContext context = new JAXBContext.newInstance(MessageObjectFactory.class);
Unmarshaller unmarshalr = context.createUnmarshaller();
this.messageTypeContent = (MessageTypeContent) unmarshalr.unmarshal(xmlSource);
The code for com.xmlprocessor.MessageTypeContent class is as such unchanged:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"messageType",
"messageApprovalType"
})
#XmlRootElement(name = "MessageType")
public class MessageTypeContent {
// Likely irrelevant unless you say so.
}
I have tried a number of things including adding namespace="ns0" or namespace="http://www.path.to/some/schema.xsd" to the #XmlRootElement annotation, it leads to similar versions of the same exception in runtime.
Please mind that there are no syntax errors in the code. Any that my have come about was in the process turning it into a question. It is entirely possible that I am a git missing out on something exteremly basic. I would really appreciate if you could point it out. Thanks.
Making the sax parser namespace aware fixed the issue:
spf.setNamespaceAware(true);
In the end, too much ado about nothing.

Convert string to JAXBElement using Java

I'm having some issue while converting String object to JAXBElement string object where I need to set this one
This is the target method where I need to set the value
public void setData(JAXBElement<String> value) {
this.data = ((JAXBElement<String> ) value);
}
For this one, I have written code something like this
ObjectFactory factory = new ObjectFactory();
JAXBElement<ApplicationIngestionRequest> jaxbElement = new JAXBElement(
new QName(ApplicationIngestionRequest.class.getSimpleName()), ApplicationIngestionRequest.class, request);
StringWriter writer = new StringWriter();
JAXBContext context = JAXBContext.newInstance(ApplicationIngestionRequest.class);
context.createMarshaller().marshal(jaxbElement, writer);
LOG.info("JAXBElement object :\n"+ writer.toString());
Unmarshaller u = context.createUnmarshaller();
JAXBElement<ApplicationIngestionRequest> o = (JAXBElement<ApplicationIngestionRequest>) u.unmarshal(new StringReader(writer));
Log gives me following output
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><ApplicationIngestionRequest><BranchCode></BranchCode><SourceCode>0000005511</SourceCode></ApplicationIngestionRequest>
Now when I try to set into the method as
losRequest.setData(o.toString());
It doesn't allow me to set as its expecting as JAXBElement format. Any ideas would be greatly appreciated.
As per the code snippet [setData(JAXBElement value)] , setData , accept instance of '(JAXBElement'). But here , you are trying to set a string value [losRequest.setData(o.toString())] . Here you have to set an instance of 'JAXBElement' .This could be the issue.

Wrap a String of an instance of JAXBElement

I have the following code,
JAXBContext jc = JAXBContext.newInstance(TestResults.class);
Marshaller m = jc.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
OutputStream os = new FileOutputStream( "nosferatu.xml" );
TestResults tr = new TestResults();
tr.setUuid(new JAXBElement<String>(new QName("uuid"),String.class, "uuidcontent"));
//ObjectFactory objectFactory = new ObjectFactory();
m.marshal(new JAXBElement<TestResults>(new QName("uri","local"),TestResults.class,new TestResults()), System.out);
in which I am trying to wrap the Java String Class as a jaxb element, since if I do not I get
the
unable to marshal type “java.lang.String” error.
However when I try wrap the java.lang.string in a jaxb element, I get the following error
The method setUuid(String) in the type TestResults is not applicable for the arguments (JAXBElement<String>)
The setUuid method looks as follows
public void setUuid(java.lang.String value) {
this.uuid = value;
}
How can I then wrap my String as a jaxb element where this error will not be thrown?
When marshalled as the root object an instance of String needs to be wrapped in a JAXBElement to provide the root element information (same as for any class without an #XmlRootElement annotation.
When marshalled as a field or property value the containing element is normally derived from the containing field/property so a JAXBElement by default is not required.

String to File (JAXB Validation)

I have a method like this.
public void myMethod(String xml){
...
File file=convertStringToFile(xml) // I need to convert xml string to File
object.fileDemandingMethod(file);
}
fileDemandingMethod(file) is expecting File but my input is string.
How can I get my xml string in the form of File object?
I need this for this JAXB Validation
Schema schema = schemaFactory.newSchema(new File("C:\\schema.xsd"));
unmarshaller.setSchema(schema );
Since you can also work with a StreamSource, you can construct a javax.xml.transform.Source from the String with:
new StreamSource(new StringReader(xml))
You don't need a file, you surely don't want the overhead of writing to a file.
setSchema() can take any object implementing javax.xml.transform.Source
StreamSource is one such class, and that can be constructed from an InputStream or Reader.
Reader reader = new StringReader(myString);
Source source = new StreamSource(reader);
unmarshaller.setSchema(spource);
The best way to do that is to create/generate a class in e.g. Employee
from your Schema (C:\Schema.xsd)
After that the rest is easy
JAXBContext context = JAXBContext.newInstance(Employee.class);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
Employee object = new Employee();
object.setCode("CA");
object.setName("Cath");
object.setSalary(300);
m.marshal(object, new FileOutputStream("result.xml"));
}

Categories

Resources