How can I marshal content to a file asynchronously using JAXB - java

I have an object that i want to marshal using JAXB and write into a file asynchronously.
I tried to write the content (of approximative 300mb) and then use AsynchronousFileChannel to write the file.
Unfortunalty it launches a java.lang.OutOfMemoryError: Java heap space during marshalling
protected String getFormattedFileContent(T fileContent) throws Exception {
StringWriter stringWriter = new StringWriter();
final JAXBContext jaxbContext = JAXBContext.newInstance(fileContent.getClass());
final Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
jaxbMarshaller.marshal(fileContent, stringWriter);
return stringWriter.toString();
}
Edit : The marshalling takes a long time to marshal the big object into XML so i launched the marshalling and the writing file into a separate Thread

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

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.

xml string to java object using jaxb

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

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

Is it possible to force JAXB to marshall illegal characters in an XML tag?

I've got a database full of objects, along with user-defined properties. For example:
class Media {
String name;
String duration;
Map<String,String> custom_tags;
}
Media:
Name: day_at_the_beach.mp4
Length: 4:22
Custom Tags:
Videographer: Charles
Owner ID #: 17a
Our users can come up with their own custom properties to attach to media, and fill in values accordingly. However, when I try to marshall the object into XML, I run into problems:
<media>
<name>day_at_the_beach.mp4</name>
<length>4:22</length>
<custom_tags>
<Videographer>Charles</videographer>
<Owner_ID_#>17a</Owner_ID_#>
</custom_tags>
</media>
Owner_ID_# is an illegal tag name in XML, because it contains a # so JAXB throws an org.w3c.dom.DOMException: INVALID_CHARACTER_ERR: An invalid or illegal XML character is specified.
I know that the preferred, correct way to solve this problem would be to reformat the xml to something along the lines of:
<custom_tags>
<custom_tag>
<name>Owner ID #</name>
<value>17z</value>
</custom_tag>
</custom_tags>
However, I'm required to return the former, invalid XML, to maintain legacy behavior from a previous, less-picky implementation of the code. Is there any way to tell JAXB not to worry about the illegal XML character, or am I going to be stuck doing a string replace before/after encoding? My current implementation is simply:
public static <T> String toXml(Object o, Class<T> z) {
try {
StringWriter sw = new StringWriter();
JAXBContext context = JAXBContext.newInstance(z);
Marshaller marshaller = context.createMarshaller();
marshaller.marshal(o, sw);
return sw.toString();
} catch (JAXBException e) {
throw new RuntimeException(e);
}
}
I built a XmlAdapter for this specific object, then:
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document document = db.newDocument();
document.setStrictErrorChecking(false); // <--- This one. This accomplished it.

Categories

Resources