I try to unmarshall one xml to ArrayList or to Class but the object which i make is not populated by JAXB
#Override
public Ships load(String xmlFilePath) {
//Ships ship = new Ships();
ArrayList<Ship> shps = new ArrayList<>();
try {
File file = new File(xmlFilePath);
JAXBContext jaxbContext = JAXBContext.newInstance(Ship.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
shps = (ArrayList<Ship>) jaxbUnmarshaller.unmarshal(file);
} catch (JAXBException e) {
e.printStackTrace();
}
return shps;}
}
Maybe you already read this solution somewhere else, but the most common solution is to make a wrapper class (or even better, a generic, reusable wrapper class). In the code below there's a working example of this concept, I hope the code is self explanatory.
package com.quick;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAnyElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD) // just to avoid the get and set methods
class Wrapper<T> {
#XmlAnyElement
List<T> list;
}
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD) // just to avoid the get and set methods
class Ship {
String id = "N" + System.nanoTime();
}
public class Main {
public static void main(String[] args) throws JAXBException {
// context, marshaller and unmarshaller
JAXBContext context = JAXBContext.newInstance(Ship.class, Wrapper.class);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
Unmarshaller unmarshaller = context.createUnmarshaller();
// original list
List<Ship> originalList = new ArrayList<>();
originalList.add(new Ship());
originalList.add(new Ship());
originalList.add(new Ship());
// wrapper object
Wrapper<Ship> originalWraper = new Wrapper<>();
originalWraper.list = originalList;
// marshal the original wrapper and save the bytes in byteArray1
ByteArrayOutputStream os1 = new ByteArrayOutputStream();
marshaller.marshal(originalWraper, os1);
byte[] byteArray1 = os1.toByteArray();
// unmarshall the bytes
ByteArrayInputStream is = new ByteArrayInputStream(byteArray1);
Wrapper<Ship> unmarshaledWrapper = (Wrapper<Ship>) unmarshaller.unmarshal(is);
// THIS LIST SHOULD CONTAIN A COPY OF originalList
List<Ship> unmarshaledList = unmarshaledWrapper.list;
// marshal the unmarshaledWrapper (...) and sabe the bytes in byteArray2
ByteArrayOutputStream os2 = new ByteArrayOutputStream();
marshaller.marshal(unmarshaledWrapper, os2);
byte[] byteArray2 = os2.toByteArray();
// print the bytes, they should be the same
System.out.println(new String(byteArray1));
System.out.println(new String(byteArray2));
}
}
The general idea is to make a class that works as a wrapper for your list (or array) that can be marshaled or marshaled according to your needs.
Related
I want to read the data from multiple XML files based on the XSD document and the structure of one XML file will not be the same as to another but will follow the xsd schema. Also, the xmls are nested xmls.Can someone help me with it so that I can use the already created utility and add the attributes to it? I need a XML parser which parses each xml file(They are different) based on the xsd schema and returns me a list of the map so that the data can be matched with the DB data.
import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
public class Test {
public static void main(String[] args) {
Customer customer = new Customer();
try {
File file = new File("SalesPoslog20200225104558676.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(Customer.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
// output pretty printed
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
jaxbMarshaller.marshal(customer, file);
jaxbMarshaller.marshal(customer, System.out);
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class Customer {
int organizationID;
int retailStoreID;
int workstationID;
int tillID;
int sequenceNumber;
public int organizationID() {
return organizationID;
}
#XmlElement
public void RetailStoreID(int retailStoreID) {
this.retailStoreID = retailStoreID;
}
public int workstationID() {
return workstationID;
}
#XmlAttribute
public void RetailStoreId(int RetailStoreId) {
this.retailStoreID = retailStoreID;
}
}
i fetched the defect url:
String defectUrl = conn.buildEntityCollectionUrl("defect");
defectUrl += "/98";
Map<String, String> requestHeaders = new HashMap<String, String>();
requestHeaders.put("Accept", "application/xml");
Response res = conn.httpGet(defectUrl, null, requestHeaders);
then converted into Entity:
String postedEntityReturnedXml = res.toString();
Entity entity = EntityMarshallingUtils.marshal(Entity.class,postedEntityReturnedXml);
than change the field value:
List<Field> fields = entity.getFields().getField();
for (Field f : fields) {
if (f.getName().equalsIgnoreCase("id"))
{
int i=f.hashCode();
System.out.println(i);
f.getValue().clear();
f.setName("");
}
}
now trying to convert it to xml formate again:
String xml = EntityMarshallingUtils.unmarshal(org.eclipse.jetty.server.Response.class,**fields**);
System.out.println(xml);
throwing error as object fields should not be there and not able to get what should i put in place of fields?
my EntityMarshallingUtils class is like:
package org.hp.qc.web.restapi.docexamples.docexamples.infrastructure;
import java.io.StringReader;
import java.io.StringWriter;
import javax.xml.bind.Marshaller;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
//import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
public class EntityMarshallingUtils {
private EntityMarshallingUtils() {}
#SuppressWarnings("unchecked")
public static <T> T marshal(Class<T> c, String xml) throws JAXBException {
T res;
if (c == xml.getClass()) {
res = (T) xml;
}
else {
JAXBContext ctx = JAXBContext.newInstance(c);
Unmarshaller marshaller = ctx.createUnmarshaller();
res = (T) marshaller.unmarshal(new StringReader(xml));
}
return res;
}
#SuppressWarnings("unchecked")
public static <T> String unmarshal(Class<T> c, Object o) throws Exception {
JAXBContext ctx = JAXBContext.newInstance(c);
Marshaller marshaller = ctx.createMarshaller();
StringWriter entityXml = new StringWriter();
marshaller.marshal(o, entityXml);
String entityString = entityXml.toString();
return entityString;
}
}
AnyOne who can help me on this?
I try to unmarshal a String using this code:
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlAnyAttribute;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.namespace.QName;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.io.IOUtils;
import org.xml.sax.InputSource;
#XmlRootElement(name="Grid")
public class Marshal {
#XmlAttribute(name="Reload", required = false)
public int reload;
#XmlElementWrapper(name="Changes")
#XmlElement(name="I")
public List<XmlAttributeHolder> rowList = new ArrayList<XmlAttributeHolder>();
public static void main(String[] args) {
try {
JAXBContext jc = JAXBContext.newInstance(Marshal.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
// à€
String xmlString = "<Grid><IO/><Changes><I id=\"0\" Changed=\"1\" STT=\"à€\"/></Changes></Grid>";
InputStream inputStream = IOUtils.toInputStream(xmlString);
InputSource is = new InputSource(inputStream);
is.setEncoding("ISO-8859-1");
Marshal obj = (Marshal) unmarshaller.unmarshal(is);
System.out.println(xmlString);
for (int i=0;i<obj.rowList.size();i++) {
XmlAttributeHolder xah = obj.rowList.get(i);
System.out.println(xah.getAttrMap());
for (String formValue:xah.getAttrMap().values()) {
System.out.println(StringEscapeUtils.unescapeXml(formValue));
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static class XmlAttributeHolder {
#XmlAnyAttribute
public Map<QName, String> attrMap = new HashMap<QName, String>();
public void addAttribute(String name, String value) {
attrMap.put(QName.valueOf(name), value);
}
public String getAttribute(String name) {
return attrMap.get(QName.valueOf(name));
}
public Map<QName, String> getAttrMap() {
return attrMap;
}
}
}
I try to run this code in Java 1.6 windows and gives the correct answer:
0
1
à€
When I try to run this code in IBM java 1.6 CentOS gives the wrong answer:
0
1
à €
Why the unmarshalling instruction doesn't convert correctly the à (even èéìòù...)?
If your input is actually a String I'd recommend passing that directly to the Unmarshaller, wrapped in a StringReader instead of trying to produce an InputStream from it. It's less error prone.
Try this (see code snippet below). Then you don't have to worry about whether your code specifies the correct encoding or does the character to byte conversion correctly for that encoding.
String xmlString = "<Grid><IO/><Changes><I id=\"0\" Changed=\"1\" STT=\"à€\"/></Changes></Grid>";
InputSource is = new InputSource(new StringReader(xmlString));
Marshal obj = (Marshal) unmarshaller.unmarshal(is);
I'm trying to marshall an object and replace some invarvalid char's after that. In this processes, the completed xml is not getting generated. I can only see 1024 chars in all the generated files.
package com.test;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.StringReader;
import java.util.Scanner;
import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.stream.StreamResult;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import org.apache.log4j.Logger;
import org.xml.sax.SAXException;
import com.sun.xml.bind.marshaller.NamespacePrefixMapper;
public class MessageParserComponent {
private static final Logger LOGGER = Logger.getLogger(MessageParserComponent.class);
public File marshalIXml(final Object obj, final String xsdSchema,
final String xmlFileName, final JAXBContext ctx) {
File xml = new File(xmlFileName);
try {
xml.createNewFile();
Marshaller marshaller = null;
marshaller = ctx.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,
Boolean.TRUE);
marshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION,
"http://www.db.com/tf " + xsdSchema);
marshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper",
new NamespacePrefixMapper() {
#Override
public String getPreferredPrefix(String arg0, String arg1,
boolean arg2) {
return "tf";
}
});
marshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION,
"http://www.db.com/tf " + xsdSchema);
marshaller.setSchema(getSchema(xsdSchema));
marshaller.marshal(obj, new StreamResult(xml));
xml = replaceInvalidChar('\u0007', '\n', xml);
xml = replaceInvalidString("ns2", "xsi", xml);
} catch (IOException e) {
LOGGER.error(e);
} catch (JAXBException e) {
LOGGER.error(e);
} catch (SAXException e) {
LOGGER.error(e);
}
return xml;
}
private Schema getSchema(String xsdSchema) throws SAXException {
SchemaFactory fact = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = fact.newSchema(this.getClass().getClassLoader()
.getResource(xsdSchema));
return schema;
}
private static File replaceInvalidString(String Target, String Dest,
File Source) throws IOException {
String xml_string;
xml_string = new Scanner(Source).useDelimiter("\\Z").next();
xml_string = xml_string.replace(Target, Dest);
FileOutputStream fi = new FileOutputStream(Source);
fi.write(xml_string.getBytes());
return Source;
}
public static File replaceInvalidChar(char Target, char Dest, File Source)
throws IOException {
String xml_string;
xml_string = new Scanner(Source).useDelimiter("\\Z").next();
xml_string = xml_string.replace(Target, Dest);
FileOutputStream fi = new FileOutputStream(Source);
fi.write(xml_string.getBytes());
return Source;
}
}
Is there a limit for string replacement?
Am I creating the file in a wrong way?
Note:
I'm storing file in UNIX log folder
I have java 6, JAXB 2.2
Any sort of help is highly appreciated.
Just check whether you annotated your object with jaxb annotations correctly.
And why are you setting Marshaller properties? do you want to use external schema to marshall your object? instead why don't you let jaxb to take care of all those things (if your objects are available in same workspace).
This sample program may be helpful to you.
http://www.mkyong.com/java/jaxb-hello-world-example/
and check this on too..
JAXB Marshaller : StringWriter output has a truncated tag value
truncated-tag-value
When you open a FileOutputStream you are responsible for closing. You should change your code to include the close() call.
FileOutputStream fi = new FileOutputStream(Source);
fi.write(xml_string.getBytes());
fi.close();
The issue was with the scanner, which is trying to find the EOF and not spooling the entire file. This is not happening in local development environment. Where as in the UNIX server, where my application is deployed the "end of input" is different, which caused this issue.
File f1 = new File(path);
StringBuilder f2 = new StringBuilder();
Scanner scanner = new Scanner(f1).useDelimiter("\\Z");
while (scanner.hasNext()) {
f2.append(scanner.next());
This completed the trick.
I do not know about the performance part of the scanner (taking only 1024 chars)when compared to other Buttered readers.
Any other solution which improves performance is highly appriciated.
I have an object value, which is of some type, either #XmlRootElement-annotated, or not. I want to marshal it into XML:
String value1 = "test";
assertEquals("<foo>test</foo>", toXml("foo", value1));
// ...
#XmlRootElement
class Bar {
public String bar = "test";
}
assertEquals("<foo><bar>test</bar></foo>", toXml("foo", new Bar()));
Can I do it with JAXB existing facilities, or I should create some custom analyzer?
You could leverage JAXBIntrospector to do the following:
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBIntrospector;
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.namespace.QName;
public class Demo {
public static void main(String[] args) throws Exception {
Object value = "Hello World";
//Object value = new Bar();
JAXBContext jc = JAXBContext.newInstance(String.class, Bar.class);
JAXBIntrospector introspector = jc.createJAXBIntrospector();
Marshaller marshaller = jc.createMarshaller();
if(null == introspector.getElementName(value)) {
JAXBElement jaxbElement = new JAXBElement(new QName("ROOT"), Object.class, value);
marshaller.marshal(jaxbElement, System.out);
} else {
marshaller.marshal(value, System.out);
}
}
#XmlRootElement
public static class Bar {
}
}
With the above code when the JAXBElement is marshalled it will be qualified with an xsi:type attribute corresponding to the appropriate schema type:
<ROOT
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:string">Hello World</ROOT>
To eliminate the qualification you can simply change the line that creates the JAXBElement to:
JAXBElement jaxbElement = new JAXBElement(new QName("ROOT"), value.getClass(), value);
This will result in the following XML:
<ROOT>Hello World</ROOT>
Here is how to marshal value1, which is a String. You can pass yourObject.getClass() to the JAXBElement constructor, and value1:
try {
JAXBContext jc = JAXBContext.newInstance();
Marshaller m = jc.createMarshaller();
String value1 = "test";
JAXBElement jx = new JAXBElement(new QName("foo"), value1.getClass(), value1);
m.marshal(jx, System.out);
} catch (JAXBException ex) {
ex.printStackTrace();
}
This works without using #XmlRootElement. The result of the code above was:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><foo>test</foo>
On the other part, this will not work with a Bar object: javax.xml.bind.JAXBException: myPackage.Bar is not known to this context. However, you can get the value from inside Bar, and create the JAXBElement with that, not the object itself.
If it's not annotated with #XmlRootElement, then JAXB does not have sufficient information to marshal it. You would need to wrap it in a JAXBElement first.
Could you do some reflective lovin' to find out how to wrap the object in the appropriate JAXBElement?
I didnt find any good generic way of doing it. Here is my generic solution.
import javax.xml.bind.*;
import javax.xml.namespace.QName;
import javax.xml.transform.stream.StreamSource;
import java.io.StringReader;
import java.io.StringWriter;
public class XMLConverter {
/**
* Serialize object to XML string
* #param object object
* #param <T> type
* #return
*/
public static <T> String marshal(T object) {
try {
StringWriter stringWriter = new StringWriter();
JAXBContext jc = JAXBContext.newInstance(object.getClass());
Marshaller m = jc.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
QName qName = new QName(object.getClass().getCanonicalName(), object.getClass().getSimpleName());
JAXBElement<T> root = new JAXBElement(qName, object.getClass(), object);
m.marshal(root, stringWriter);
return stringWriter.toString();
} catch (Exception e) {
// log the exception
}
return null;
}
/**
* Deserialize XML string back to object
* #param content XML content
* #param clasz class
* #param <T> type
* #return
*/
public static <T> T unMarshal(final String content, final Class<T> clasz) {
try {
JAXBContext jc = JAXBContext.newInstance(clasz);
Unmarshaller u = jc.createUnmarshaller();
return u.unmarshal(new StreamSource(new StringReader(content)), clasz).getValue();
} catch (Exception e) {
// log the exception
}
return null;
}
}