How to unmarshal list element using JAXB - java

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

Related

unmarshaling always shows 0 and null

I think the best way is to copy my code so you can understand it.
Here are my POJO classes:
import javax.xml.bind.annotation.XmlAttribute;
public class Product {
private String name;
public Product() {
}
public Product(String name) {
this.name = name;
}
#XmlAttribute(name = "productName")
public String getProduct() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name="ShoppingCart")
public class Cart {
private List<Product> productList = new ArrayList<>();
private long CartIdentifier;
public Cart() {
}
public Cart(long id) {
this.CartIdentifier=id;
}
#XmlAttribute(name="CartIdentifier")
public long getId() {
return CartIdentifier;
}
public void setType(long id) {
this.CartIdentifier=id;
}
public Cart(List<Product> list) {
this.productList = list;
}
public void addElement(Product element) {
this.productList.add(element);
}
#XmlElement(name = "CurrentProducts")
public List<Product> getCart() {
return this.productList;
}
public void setCart(List<Product> cart) {
this.productList = cart;
}
}
import java.util.ArrayList;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name = "CashRegister")
public class Register {
#XmlElement(name = "ShoppingCart")
private ArrayList<Cart> listCart;
long CartIdentifier;
public Register() {
}
public Register(long id) {
this.CartIdentifier=id;
}
public long getId() {
return CartIdentifier;
}
public void addElementforBonus(Cart element) {
listCart.add(element);
}
public void setType(long id) {
this. CartIdentifier=id;
}
public void setList(ArrayList<Cart> list) {
this.listCart = list;
}
public ArrayList<Cart> getCartList() {
return listCart;
}
}
So those are my POJO classes and in main they create perfect XML, but when it comes to converting from XML to normal output something goes wrong. Can someone tell me where am I making mistake and why is my output than alway 0 and null?
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
public class Main {
public static void main(String[] args) throws JAXBException, IOException {
ArrayList<Cart> list = new ArrayList<Cart>();
Register store = new Register(1);
store.setType(1);
store.setList(list);
Product first = new Product("Burger");
Product second = new Product("Banana");
Cart cart1 = new Cart(1);
cart1.setType(1);
cart1.addElement(first);
cart1.addElement(second);
store.getCartList().add(cart1);
// create JAXB context and instantiate marshaller
JAXBContext context = JAXBContext.newInstance(Register.class);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
// Write to System.out
m.marshal(store, System.out);
m.marshal(store, new File("mrs.xml"));
System.out.println("Output from our XML File: ");
Unmarshaller um = context.createUnmarshaller();
Register reg = (Register) um.unmarshal(new FileReader("mrs.xml"));
ArrayList<Cart> list1 = reg.getCartList();
for(Cart x:reg.getCartList()) {
System.out.println(x.getId());
}
for (Cart cart : list1) {
System.out.println("Cart: " + cart.getId());
for(Product product : cart.getCart()) {
System.out.println("Product: " + product.getProduct());
}
}
}
}
So here is my output:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<CashRegister>
<ShoppingCart CartIdentifier="1">
<CurrentProducts productName="Burger"/>
<CurrentProducts productName="Banana"/>
</ShoppingCart>
</CashRegister>
Output from our XML File:
0
Cart: 0
Product: null
Product: null
There is one cart with two products but not with 0 and null.
No, my question isn't duplicate. I don't want to have that as Element or show the name of that element in my xml. My xml looks perfect but i can't unmarshal it
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<CashRegister>
<ShoppingCart CartIdentifier="1">
<CurrentProducts productName="Burger"/>
<CurrentProducts productName="Banana"/>
</ShoppingCart>
</CashRegister>
Output from our XML File:
Exception in thread "main" java.lang.ClassCastException: bonusxml.Register cannot be cast to bonusxml.Register1
at bonusxml.Main.main(Main.java:45)
If you are hell bent on preserving your XML structure, you will have to pay a price for that. Below, are classes that can get you de-serializing the XML you have created. But, you will end up using two different set of classes for serializing and de-serializing.
Cart.java
#XmlRootElement(name="ShoppingCart")
public class Cart1 {
#XmlElement(name = "CurrentProducts")
private List<Product1> productList = new ArrayList<>();
#XmlAttribute(name="CartIdentifier")
private long CartIdentifier;
public Cart1() {}
public Cart1(long id) {
this.CartIdentifier=id;
}
// setters & getters
}
Product.java
public class Product1 {
#XmlAttribute(name = "productName")
private String name;
public Product1() {
}
public Product1(String name) {
this.name = name;
}
// setters & getters
}
Register.java
#XmlRootElement(name = "CashRegister")
public class Register1 {
#XmlElement(name = "ShoppingCart")
private ArrayList<Cart1> listCart;
long CartIdentifier;
public Register1() {
}
public Register1(long id) {
this.CartIdentifier=id;
}
//setters & getters
}

Unable to Unmarshall a xml in java using JAXB without using any annotation- No error but Unmarshalling is incorrect

I am trying to Convert XML content into a Java Object using JAXB without using any annotation. My XML file (CustomerDtl.xml) structure is mentioned below
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<basePojo>
<customerId>C001</customerId>
<customerList>
<Customer>
<name>Ram</name>
<phoneNo>123445</phoneNo>
</Customer>
<Customer>
<name>Tom</name>
<phoneNo>2332322</phoneNo>
</Customer>
</customerList>
</basePojo>
and my pojos are
BasePojo.java
package pojo;
import java.util.List;
import pojo.Customer;
public class BasePojo {
List<Customer> customerList;
String customerId;
public List<Customer> getCustomerList() {
return customerList;
}
public void setCustomerList(List<Customer> customerList) {
this.customerList = customerList;
}
public String getCustomerId() {
return customerId;
}
public void setCustomerId(String customerId) {
this.customerId = customerId;
}
}
Customer.java
package pojo;
public class Customer {
private String name;
private String phoneNo;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhoneNo() {
return phoneNo;
}
public void setPhoneNo(String phoneNo) {
this.phoneNo = phoneNo;
}
}
Below mentioned piece of code I have written to Convert XML content into a Java Object
try {
JAXBContext jc = JAXBContext.newInstance(BasePojo.class);
StreamSource xml = new StreamSource("CustomerDtl.xml");
Unmarshaller unmarshaller = jc.createUnmarshaller();
JAXBElement<BasePojo> jaxbElementObject = unmarshaller.unmarshal(
xml, BasePojo.class);
BasePojo bPojo = jaxbElementObject.getValue();
System.out.println("id="+bPojo.getCustomerId());
System.out.println("list size="+bPojo.getCustomerList().size());
Iterator iterator = bPojo.getCustomerList().iterator();
while (iterator.hasNext()) {
Customer studentDetails = (Customer) iterator.next();
System.out.println("Print Name:" + studentDetails.getName());
}
} catch (JAXBException e) {
System.out.println("Exception:" + e);
}
And the out put of this code is
id=C001
list size=1
list size=[pojo.Customer#3e3abc88]
Print Customer Name:null
After executing this program it's prints the correct customerId, but it prints the wrong customer list size 1. Although the list size is 1, and the list contains Customer object but when I iterate through the list and try to get different property value of Customer, I am getting null.
Can any one explain me what I need to correct? Using annotation I tried and it is working as expected. Is it not possible without annotation?
In the xml you don't have to specify the class name (Customer) as the child of your list (customerList), just use the list name directly for every element.
So, change the xml like this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<basePojo>
<customerId>C001</customerId>
<customerList>
<name>Ram</name>
<phoneNo>123445</phoneNo>
</customerList>
<customerList>
<name>Tom</name>
<phoneNo>2332322</phoneNo>
</customerList>
</basePojo>
Try something like below
try {
XMLInputFactory xif = XMLInputFactory.newFactory();
StreamSource xml = new StreamSource("CustomerDtl.xml");
XMLStreamReader xsr = xif.createXMLStreamReader(xml);
while(xsr.hasNext()) {
if(xsr.isStartElement() && "Customer".equals(xsr.getLocalName())) {
break;
}
xsr.next();
}
JAXBContext jc = JAXBContext.newInstance(Customer.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
Customer customer = unmarshaller.unmarshal(xsr, Customer.class).getValue();
System.out.println(customer.getName());
} catch (JAXBException e) {
System.out.println("Exception:" + e);
}
Here you go if you do not want any annotation (with exact xml that you shared).
1) Wrap your list to a wrapper class (to handle customerList)
2) Now as I asked in Comment, if you have "Customer" element, then default "xml" name recognized will be with small c. If you don't want to annotate even that, then handle it while reading it.
After having said so here is an working sample (with runnable main) modifying your BasePojo
package pojo;
import java.io.ByteArrayInputStream;
import java.io.StringReader;
import java.util.Iterator;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Unmarshaller;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.util.StreamReaderDelegate;
import javax.xml.transform.stream.StreamSource;
public class BasePojo {
String customerId;
CustomerList customerList;
public CustomerList getCustomerList() {
return customerList;
}
public void setCustomerList(CustomerList customerListObject) {
this.customerList = customerListObject;
}
public String getCustomerId() {
return customerId;
}
public void setCustomerId(String customerId) {
this.customerId = customerId;
}
public static void main(String[] args) {
try {
String customerData = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n"
+ "<basePojo>\n"
+ "<customerId>C001</customerId>\n"
+ "<customerList>\n"
+ " <Customer>\n"
+ " <name>Ram</name>\n"
+ " <phoneNo>123445</phoneNo>\n"
+ " </Customer>\n"
+ "\n"
+ " <Customer>\n"
+ " <name>Tom</name>\n"
+ " <phoneNo>2332322</phoneNo>\n"
+ " </Customer>\n"
+ "</customerList>\n"
+ "</basePojo>";
JAXBContext jc = JAXBContext.newInstance(BasePojo.class);
StringReader reader = new StringReader(customerData);
StreamSource xml = new StreamSource(reader);
XMLInputFactory xif = XMLInputFactory.newFactory();
XMLStreamReader xsr = xif.createXMLStreamReader(new ByteArrayInputStream(customerData.getBytes("UTF-8")));
xsr = new StreamReaderDelegate(xsr) {
#Override
public String getLocalName() {
String localName = super.getLocalName();
if ("Customer".equals(localName)) {
return "customer";
}
return localName;
}
};
Unmarshaller unmarshaller = jc.createUnmarshaller();
JAXBElement<BasePojo> jaxbElementObject = unmarshaller.unmarshal(xsr, BasePojo.class);
BasePojo bPojo = jaxbElementObject.getValue();
System.out.println("id=" + bPojo.getCustomerId());
System.out.println("list size=" + bPojo.getCustomerList().getCustomer().size());
Iterator iterator = bPojo.getCustomerList().getCustomer().iterator();
while (iterator.hasNext()) {
Customer studentDetails = (Customer) iterator.next();
System.out.println("Print Name:" + studentDetails.getName());
}
} catch (Exception e) {
System.out.println("Exception:" + e);
}
}
}
class CustomerList {
private List<Customer> customer;
public List<Customer> getCustomer() {
return customer;
}
public void setCustomer(List<Customer> customer) {
this.customer = customer;
}
}

JAXB unmarshalling without XmlRootElement annotation?

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

Java Unmarshal list of objects with a class wrapper with JAXB

From an XQuery performed by BaseX server I get a result like that:
<ProtocolloList>
<protocollo>
<numero>1</numero>
<data>2014-06-23</data>
<oggetto/>
<destinatario/>
<operatore/>
</protocollo>
...
</ProtocolloList>
And I need to convert this result in a List of Protocollo objects with JAXB so that I can show them with JList. Thus, following one of the discussions here I've declared the following classes:
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name = "protocollo")
public class Protocollo {
private int numero;
private String data;
private String oggetto;
private String destinatario;
private String operatore;
public Protocollo(String d, String o, String des, String op) {
this.data = d;
this.oggetto = o;
this.destinatario = des;
this.operatore = op;
}
public Protocollo() {
}
#XmlElement
public int getNumero() {
return numero;
}
public void setNumero(int numero) {
this.numero = numero;
}
#XmlElement
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
#XmlElement
public String getOggetto() {
return oggetto;
}
public void setOggetto(String oggetto) {
this.oggetto = oggetto;
}
#XmlElement
public String getDestinatario() {
return destinatario;
}
public void setDestinatario(String destinatario) {
this.destinatario = destinatario;
}
#XmlElement
public String getOperatore() {
return operatore;
}
public void setOperatore(String operatore) {
this.operatore = operatore;
}
}
and
import java.util.ArrayList;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name = "ProtocolloList")
public class ProtocolloList {
#XmlElementWrapper(name = "ProtocolloList")
#XmlElement(name = "protocollo")
private ArrayList<Protocollo> ProtocolloList;
public ArrayList<Protocollo> getProtocolloList() {
return ProtocolloList;
}
public void setProtocolloList(ArrayList<Protocollo> protocolloList) {
ProtocolloList = protocolloList;
}
}
and finally I execute the converion like that:
JAXBContext jaxbContext = JAXBContext.newInstance(Protocollo.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
StringReader reader = new StringReader(this.resultXML);
protocolli = (ProtocolloList) unmarshaller.unmarshal(reader);
And I keep on getting this exception:
unexpected element (uri:"", local:"ProtocolloList"). Expected elements are <{}protocollo>
I suppose I'm making some mistakes with annotations.
Can you help?
For your use case you do not need the #XmlElementWrapper annotation. This is because the ProtocolList element corresponds to your #XmlRootElement annotation. Then you need the #XmlElement annotation on the property to grab each of the list items.
#XmlRootElement(name = "ProtocolloList")
public class ProtocolloList {
private ArrayList<Protocollo> ProtocolloList;
#XmlElement(name = "protocollo")
public ArrayList<Protocollo> getProtocolloList() {
return ProtocolloList;
}
}
Note:
By default you should annotate the property. If you want to annotate the fields you should put #XmlAccessorType(XmlAccessType.FIELD) on your class.
UPDATE
You need to make sure your JAXBContext is aware of the root class. You can change your JAXBContext creation code to be the following:
JAXBContext jaxbContext = JAXBContext.newInstance(ProtocolloList.class);

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

Categories

Resources