JAXB unmarshalling without XmlRootElement annotation? - java

Is there any way we can un-marshall for a class without #XmlRootElement annotation? Or are we obligated to enter the annotation?
for example:
public class Customer {
private String name;
private int age;
private int id;
public String getName() {
return name;
}
#XmlElement
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
#XmlElement
public void setAge(int age) {
this.age = age;
}
public int getId() {
return id;
}
#XmlAttribute
public void setId(int id) {
this.id = id;
}
}
and let the unmarshalling code for properly annotated class be like:
try {
File file = new File("C:\\file.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(Customer.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
Customer customer = (Customer) jaxbUnmarshaller.unmarshal(file);
System.out.println(customer);
} catch (JAXBException e) {
e.printStackTrace();
}
leaving out the details.

Following code is used to marshall and unmarshall withot #XmlRootElement
public static void main(String[] args) {
try {
StringWriter stringWriter = new StringWriter();
Customer c = new Customer();
c.setAge(1);
c.setName("name");
JAXBContext jaxbContext = JAXBContext.newInstance(Customer.class);
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.marshal(new JAXBElement<Customer>( new QName("", "Customer"), Customer.class, null, c), stringWriter);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
InputStream is = new ByteArrayInputStream(stringWriter.toString().getBytes());
JAXBElement<Customer> customer = (JAXBElement<Customer>) jaxbUnmarshaller.unmarshal(new StreamSource(is),Customer.class);
c = customer.getValue();
} catch (JAXBException e) {
e.printStackTrace();
}
}
Above code works only if you adding #XmlAccessorType(XmlAccessType.PROPERTY) on Customer class, or make private all attributes.

If you cannot add XmlRootElement to existing bean you can also create a holder class and mark it with annotation as XmlRootElement. Example below:-
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class CustomerHolder
{
private Customer cusotmer;
public Customer getCusotmer() {
return cusotmer;
}
public void setCusotmer(Customer cusotmer) {
this.cusotmer = cusotmer;
}
}

It is indisputable that the question is very old for an answer, however still hoping someone like me is looking for a simple generic code snippet for the above requirement, hence sharing the working solution for the marshal and unmarshal need.
Marshalling XML object to String
public static <T> Optional<String> objectToXMLString(T value,Class<T> clazz,String rootElement) {
StringWriter sw = new StringWriter();
try {
JAXBContext jaxbContext = JAXBContext.newInstance(clazz);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
JAXBElement<T> jaxbElement = new JAXBElement<>(new QName(rootElement), clazz,value);
jaxbMarshaller.marshal(jaxbElement, sw);
return Optional.of(sw.toString());
} catch (JAXBException e) {
LOGGER.error("XML to String Conversion exception:{}", e.getMessage(), e);
}
return Optional.empty();
}
UnMarshalling String to XML object
public static <T> Optional<T> xmlStringToObject(String value, Class<T> clazz) {
try {
JAXBContext jaxbContext = JAXBContext.newInstance(clazz);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
InputStream is = new ByteArrayInputStream(value.getBytes());
JAXBElement<T> object = unmarshaller.unmarshal(new StreamSource(is),clazz);
return Optional.of(object.getValue());
} catch (JAXBException e) {
LOGGER.error("String to XML Conversion exception : {}", e.getMessage(), e);
}
return Optional.empty();
}

Related

Getting null when converting xml into java object

Here is my code
class
#Data
#XmlRootElement(name = "ASX", namespace = "urn:synt:aps:zion")
#XmlAccessorType(XmlAccessType.FIELD)
public class Cpix {
#XmlElement(name = "ZionicList")
private ZionicList zionicList;
#XmlElement(name = "Abrah")
private AbrahList abrahList;
}
rsp
<ns2:ASX xmlns="urn:djwfw:fwd2" xmlns:ns2="urn:synt:aps:zion">
<ns2:ZionicList>
....
</ns2:ZionicList>
<ns2:Abrah>
....
</ns2:Abrah>
</ns2:ASX>
Converter
public static <T> T convertXmlToObject(String response, Class<T> clazz) {
try {
JAXBContext context = JAXBContext.newInstance(clazz);
Unmarshaller unmarshaller = context.createUnmarshaller();
return (T) unmarshaller.unmarshal(new StringReader(response));
} catch (JAXBException e) {
fail(e.getMessage());
}
return null;
}
In the end Im getting null for ZionicList and AbrahList
It's ok when Im explicitly adding namespace to each xmlElement attribute
#Data
#XmlRootElement(name = "ASX", namespace = "urn:synt:aps:zion")
#XmlAccessorType(XmlAccessType.FIELD)
public class Cpix {
#XmlElement(name = "ZionicList", namespace = "urn:synt:aps:zion")
private ZionicList zionicList;
#XmlElement(name = "Abrah", namespace = "urn:synt:aps:zion")
private AbrahList abrahList;
}

How to unmarshal list element using JAXB

Need help in reading the attirubutes and values of the list EmployeeParamData and EmployeeParam
My XML is
<HostedEmployee>
<employeeid>12345</employeeid>
<employeeage>26</employeeage>
<employeeParamData>
<employeeParam name="attribute1"/>
<employeeParam name="attribute2">attribute2_value</employeeParam>
<employeeParam name="attribute3">attribute3_value</employeeParam>
<employeeParam name="attribute4">attribute4_value</employeeParam>
<employeeParam name="attribute5"/>
</employeeParamData>
</HostedEmployee>
My domain class is :
import java.util.List;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name="HostedEmployee")
public class HostedEmployee {
private String employeeId;
public String getEmployeeId() {
return employeeId;
}
#XmlElement
public void setEmployeeId(String employeeId) {
this.employeeId= employeeId;
}
}
and the unmarshalling is done here
public static void main(String[] args) {
try {
File file = new File(".../jaxbtest.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(HostedEmployee.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
HostedEmployee hostedEmployee= (HostedEmployee) jaxbUnmarshaller.unmarshal(file);
System.out.println(hostedEmployee.getEventGuid());
} catch (JAXBException e) {
e.printStackTrace();
}
}

How to name complex objects in JAXB/JSON?

#XmlRootElement(name = "test")
public class MyDTO {
#XmlElement(name = "test2)
private MyObject meta;
}
Result:
{meta:{...}}
Problems:
I'd like to have some kind of "outer" tag named "test"
Why is the #XmlElement(name" attribute for meta not working?
my first post!
Indeed you can name your "outer" tag with #XmlRootElement. If you need another outer tag I am not sure how to realize this.
Your second concern might be because of the place where you put the #XmlElement. I placed it on my getter-method and it worked fine fore me.
For the JSON Output I used jersey-json-1.18.
The following works also for other complex types you could define instead of "String meta".
Here is the output I was able to produce:
As JSON
{"myId":"id1","myMeta":"text1"}
As XML
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<mytupel>
<myId>id1</myId>
<myMeta>text1</myMeta>
</mytupel>
This is my object:
#XmlRootElement(name = "mytupel")
public class Tupel {
// #XmlElement(name = ) does not work here - defined it on the getter method
private String id;
// #XmlElement(name = ) does not work here - defined it on the getter method
private String meta;
/**
* Needed for JAXB
*/
public Tupel() {
}
/**
* For Test purpose...
*/
public Tupel(String id, String text) {
super();
this.id = id;
this.meta = text;
}
#XmlElement(name = "myId")
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
#XmlElement(name = "myMeta")
public String getMeta() {
return meta;
}
public void setMeta(String meta) {
this.meta = meta;
}
/**
* For Test purpose...
*/
#Override
public String toString() {
return id + ": " + meta;
}
}
And here is my small class to produce the output XML files...
public class Main {
private static final String TUPEL_1_XML = "./tupel1.xml";
private static final String TUPEL_2_XML = "./tupel2.xml";
public static void main(String[] args) throws JAXBException, FileNotFoundException {
// init JAXB context/Marhsaller stuff
JAXBContext context = JAXBContext.newInstance(Tupel.class);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
Unmarshaller unmarshaller = context.createUnmarshaller();
// create some Datatypes
Tupel data1 = new Tupel("id1", "text1");
Tupel data2 = new Tupel("id2", "42");
// produce output
marshaller.marshal(data1, new File(TUPEL_1_XML));
marshaller.marshal(data2, new File(TUPEL_2_XML));
// read from produced output
Tupel data1FromXml = (Tupel) unmarshaller.unmarshal(new FileReader(TUPEL_1_XML));
Tupel data2FromXml = (Tupel) unmarshaller.unmarshal(new FileReader(TUPEL_2_XML));
System.out.println(data1FromXml.toString());
System.out.println(data2FromXml.toString());
System.out.println(marshalToJson(data1FromXml));
System.out.println(marshalToJson(data2FromXml));
}
public static String marshalToJson(Object o) throws JAXBException {
StringWriter writer = new StringWriter();
JAXBContext context = JSONJAXBContext.newInstance(o.getClass());
Marshaller m = context.createMarshaller();
JSONMarshaller marshaller = JSONJAXBContext.getJSONMarshaller(m, context);
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshallToJSON(o, writer);
return writer.toString();
}
}
Hope this answers your question!
Cheers
Max

Exception in thread "main" java.lang.NullPointerException when using Jaxb unmarshal/marshal

I'm using JAXB to unmarshal a given input Xml file into Java object
and then marashal it back to Xml String.
My Xml file looks like this:
<bpmn2:definitions xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL" id="_Definitions_1">
<bpmn2:process id="_500441" name="process">
</bpmn2:process>
</bpmn2:definitions>
Definitions.class:
#XmlRootElement(namespace = "http://www.omg.org/spec/BPMN/20100524/MODEL")
public class Definitions {
#XmlAttribute
private String id;
#XmlElement(name = "bpmn2:process")
private Process process;
#XmlElement(name = "bpmndi:BPMNDiagram")
private Diagram diagram;
public Definitions() {
}
public Definitions(String id, Process process, Diagram diagram) {
this.id = id;
this.process = process;
this.diagram = diagram;
}
public Process getProcess() {
return process;
}
public Diagram getDiagram() {
return diagram;
}
public String getId() {
return id;
}
}
Process.class:
#XmlAccessorType(XmlAccessType.FIELD)
public class Process {
#XmlAttribute
private String id;
public Process() {
}
public Process(String id) {
this.id = id;
}
public String getId() {
return id;
}
}
Model.class:
public class Model {
#XmlElement
private Process process;
public Model() {
}
public Model(String processId, Process p) {
this.id = processId;
this.process = p;
}
}
main method:
public static void main(String[] args) throws IOException, JSONException, JAXBException {
BpmnToJsonImport bj = new BpmnToJsonImport();
InputStream is = BpmnToJsonImport.class.getResourceAsStream("myXml.txt");
String Str = IOUtils.toString(is);
StringReader sr = new StringReader(Str);
JAXBContext context = JAXBContext.newInstance(Definitions.class, Model.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
Definitions d = (Definitions) unmarshaller.unmarshal(sr);
Model model = new Model(d.getProcess().getId(), d.getProcess());
StringWriter sw = new StringWriter();
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
marshaller.marshal(model, sw);
String str = sw.toString();
System.out.println(str);
}
Exactly when it tries to retrieve the process id using d.getProcess.getId I get the
java.lang.NullPointerException
You are mapping the namespace qualification incorrectly. You must not include the prefix in the element name.
#XmlElement(name = "BPMNDiagram")
private Diagram diagram;
To map the namespace qualification you can use the package level #XmlSchema annotation.
package-info.java
#XmlSchema(
namespace = "http://www.omg.org/spec/BPMN/20100524/MODEL",
elementFormDefault = XmlNsForm.QUALIFIED)
package example;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
For More Information
http://blog.bdoughan.com/2010/08/jaxb-namespaces.html

JAXB Marshalling Objects with java.lang.Object field

I'm trying to marshal an object that has an Object as one of its fields.
#XmlRootElement
public class TaskInstance implements Serializable {
...
private Object dataObject;
...
}
The dataObject can be one of many different unknown types, so specifying each somewhere is not only impractical but impossible. When I try to marshal the object, it says the class is not known to the context.
MockProcessData mpd = new MockProcessData();
TaskInstance ti = new TaskInstance();
ti.setDataObject(mpd);
String ti_m = JAXBMarshall.marshall(ti);
"MockProcessData nor any of its super class is known to this context." is what I get.
Is there any way around this error?
JAXB cannot marshal any old object, since it doesn't know how. For example, it wouldn't know what element name to use.
If you need to handle this sort of wildcard, the only solution is to wrap the objects in a JAXBElement object, which contains enough information for JAXB to marshal to XML.
Try something like:
QName elementName = new QName(...); // supply element name here
JAXBElement jaxbElement = new JAXBElement(elementName, mpd.getClass(), mpd);
ti.setDataObject(jaxbElement);
Method:
public String marshallXML(Object object) {
JAXBContext context;
try {
context = JAXBContext.newInstance(object.getClass());
StringWriter writer = new StringWriter();
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(object, writer);
String stringXML = writer.toString();
return stringXML;
} catch (JAXBException e) {
}
}
Model:
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class Customer {
String name;
int id;
public String getName() {
return name;
}
#XmlElement
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
#XmlAttribute
public void setId(int id) {
this.id = id;
}
}

Categories

Resources