JAXB Marshalling extra element in XML - java

I have the following Employee class which i need to represent in XML format
Employee:
#XmlRootElement(name="employee")
#XmlAccessorType(XmlAccessType.FIELD)
public class Employee {
private int id;
private String firstName;
private String lastName;
private int income;
private Map<Integer,Employee> employeeMap=new HashMap<>();
//getters and setters
}
Marshalling code:
public class MarshallExample {
public static void main(String[] args) throws JAXBException {
Map<Integer,Employee> empMap=new HashMap<>();
Employee emp1=new Employee();
emp1.setId(1);
emp1.setFirstName("aa");
emp1.setLastName("bb");
emp1.setIncome(1000);
Employee emp2=new Employee();
emp2.setId(2);
emp2.setFirstName("xx");
emp2.setLastName("yy");
emp2.setIncome(2000);
empMap.put(1, emp1);
empMap.put(2, emp2);
Employee emp=new Employee();
emp.setEmployeeMap(empMap);
JAXBContext jaxbContext=JAXBContext.newInstance(Employee.class);
Marshaller jaxbMarshaller=jaxbContext.createMarshaller();
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
jaxbMarshaller.marshal(emp, System.out);
}
}
XML Output:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<employee>
<id>0</id>
<income>0</income>
<employeeMap>
<entry>
<key>1</key>
<value>
<id>1</id>
<firstName>aa</firstName>
<lastName>bb</lastName>
<income>1000</income>
<employeeMap/>
</value>
</entry>
<entry>
<key>2</key>
<value>
<id>2</id>
<firstName>xx</firstName>
<lastName>yy</lastName>
<income>2000</income>
<employeeMap/>
</value>
</entry>
</employeeMap>
</employee>
Not able to figure out why the <id> 0 </id> and <income> 0 </income> element are present in the output inside the root element instead of just the two employee instances.

It is because that are int values and can not be null. Change it to Integer an they will not longer rendered.
#XmlRootElement(name="employee")
#XmlAccessorType(XmlAccessType.FIELD)
public class Employee {
private Integer id;
private String firstName;
private String lastName;
private Integer income;
private Map<Integer,Employee> employeeMap=new HashMap<>();
//getters and Setters
}

Related

a nested xml unmarshalling using jaxb

I have an xml structure as follows:
<?xml version="1.0" encoding="UTF-8"?>
<school>
<students>
<student>
<firstName>A</firstName>
<id>1</id>
<lastName>C</lastName>
<company>BCD</company>
<responsibilities>
<responsibility>Leader</responsibility>
<responsibility>Dancer</responsibility>
<responsibility>Reporter</responsibility>
</responsibilities>
</student>
<student>
<firstName>B</firstName>
<id>2</id>
<lastName>C</lastName>
<company>EFG</company>
<responsibilities>
<responsibility>Singer</responsibility>
</responsibilities>
</student>
</students>
<Teachers>
<Teacher>
<firstName>A</firstName>
<lastName>C</lastName>
<responsibilities>
<responsibility>English</responsibility>
<responsibility>Hindi</responsibility>
<responsibility>Softskills</responsibility>
</responsibilities>
</Teacher>
<Teacher>
<firstName>A</firstName>
<lastName>C</lastName>
<company>BCD</company>
<responsibilities>
<responsibility>Science</responsibility>
<responsibility>Math</responsibility>
</responsibilities>
</Teacher>
</Teachers>
</school>
I would want to dynamically parse all the objects and put it into a list.
I have created classes for school,students,student,teacher,teacehrs,responsibilities, responsibility.
These are shown below:
import lombok.Data;
#Data
#XmlRootElement(name="school")
public class School {
private List<Students> Students;
private List<Teachers> Teachers;
}
#Data
public class Students {
private List<Student> student;
}
#Data
public class Student {
private long Id;
private String firstName;
private String lastName;
private String company;
private Responsibilities Responsibilities;
}
#XmlAccessorType(XmlAccessType.PROPERTY)
public class Responsibilities {
public List<String> responsibility ;
}
public class Responsibility {
private String responsibility;
}
#Data
public class Teachers {
private List<Teacher> teacher;
}
public class Teacher {
private String firstName;
private String lastName;
private String company;
private Responsibilities Responsibilities;
}
Also i have the main parsing file, where i want to generically pass all the objects through the root tag (school).
public class ParsingXML {
public static void main(String[] args) {
// TODO Auto-generated method stub
List<School> Entries = new ArrayList<School>();
try {
File xmlFile = new File("Student.xml");
JAXBContext jaxbContext;
jaxbContext = JAXBContext.newInstance(School.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
School entries = (School) jaxbUnmarshaller.unmarshal(xmlFile);
Entries.add(entries);
/*
* for(Student s: students.getStudent()) { System.out.println(s); }
*/
}
catch (JAXBException e)
{
e.printStackTrace();
}
ListIterator<School> litr = Entries.listIterator();
System.out.println(Entries.size());
//System.out.println("\n Using list iterator");
while(litr.hasNext()){
System.out.println(litr.next());
}
}
}
I expect to get Teachers entries too.. But I get ony students here.
Output:
School(Students=[Students(student=[Student(Id=1, firstName=A, lastName=C, company=BCD, Responsibilities=Responsibilities(responsibility=[Leader, Dancer, Reporter])), Student(Id=2, firstName=B, lastName=C, company=EFG, Responsibilities=Responsibilities(responsibility=[Singer]))])], Teachers=null)
Please suggest me my mistakes and provide me some guidance here
The following code would work for you:
School.class
#XmlRootElement(name = "school")
#Data
#XmlAccessorType(XmlAccessType.FIELD)
public class School {
#XmlElementWrapper(name="students")
#XmlElement(name="student")
private List<Student> students;
#XmlElementWrapper(name="Teachers")
#XmlElement(name="Teacher")
private List<Teacher> responsibilities;
}
Teacher.class:
#Data
#XmlAccessorType(XmlAccessType.NONE)
public class Teacher {
#XmlElement(name="firstName")
private String firstName;
#XmlElement(name="lastName")
private String lastName;
#XmlElementWrapper(name="responsibilities")
#XmlElement(name="responsibility")
private List<String> responsibilities;
}
Student.class:
#Data
#XmlAccessorType(XmlAccessType.NONE)
public class Student {
#XmlElement(name="id")
private long Id;
#XmlElement(name="firstName")
private String firstName;
#XmlElement(name="lastName")
private String lastName;
#XmlElement(name="company")
private String company;
#XmlElementWrapper(name="responsibilities")
#XmlElement(name="responsibility")
private List<String> responsibilities;
}
Main.class:
public class Main {
public static void main(String[] args) throws JAXBException, XMLStreamException {
final InputStream inputStream = Main.class.getClassLoader().getResourceAsStream("students.xml");
final XMLStreamReader xmlStreamReader = XMLInputFactory.newInstance().createXMLStreamReader(inputStream);
final Unmarshaller unmarshaller = JAXBContext.newInstance(School.class).createUnmarshaller();
final School school = unmarshaller.unmarshal(xmlStreamReader, School.class).getValue();
System.out.println(school.toString());
Marshaller marshaller = JAXBContext.newInstance(School.class).createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.marshal(school, System.out);
}
}
Following is the output:
School(students=[Student(Id=1, firstName=A, lastName=C, company=BCD, responsibilities=[Leader, Dancer, Reporter]), Student(Id=2, firstName=B, lastName=C, company=EFG, responsibilities=[Singer])], responsibilities=[Teacher(firstName=A, lastName=C, responsibilities=[English, Hindi, Softskills]), Teacher(firstName=A, lastName=C, responsibilities=[Science, Math])])
<school>
<students>
<student>
<id>1</id>
<firstName>A</firstName>
<lastName>C</lastName>
<company>BCD</company>
<responsibilities>
<responsibility>Leader</responsibility>
<responsibility>Dancer</responsibility>
<responsibility>Reporter</responsibility>
</responsibilities>
</student>
<student>
<id>2</id>
<firstName>B</firstName>
<lastName>C</lastName>
<company>EFG</company>
<responsibilities>
<responsibility>Singer</responsibility>
</responsibilities>
</student>
</students>
<Teachers>
<Teacher>
<firstName>A</firstName>
<lastName>C</lastName>
<responsibilities>
<responsibility>English</responsibility>
<responsibility>Hindi</responsibility>
<responsibility>Softskills</responsibility>
</responsibilities>
</Teacher>
<Teacher>
<firstName>A</firstName>
<lastName>C</lastName>
<responsibilities>
<responsibility>Science</responsibility>
<responsibility>Math</responsibility>
</responsibilities>
</Teacher>
</Teachers>
</school>

PropertyNotFoundException: Could not find a setter

Suppose I have such entity:
public class Foo {
private long id;
private List<Bar> list = new ArrayList<>();
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public List<Bar> getList() {
return list;
}
public void setList(List<Bar> list) {
this.list = list;
}
/** helper method*/
public boolean isEmpty(){
return list.isEmpty();
}
}
And corresponding entity mapping:
<?xml version="1.0" encoding="UTF-8" ?>
<entity-mappings xmlns="http://xmlns.jcp.org/xml/ns/persistence/orm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence/orm"
version="2.1">
<entity class="Foo">
<table name="foo"/>
<attributes>
<id name="id"/>
<one-to-many name="list">
<!-- ... -->
</one-to-many>
<transient name="isEmpty"/>
</attributes>
</entity>
</entity-mappings>
And this exception I got:org.hibernate.PropertyNotFoundException: Could not locate setter method for property [Foo#empty]
I found a similar post - HIbernate Mapping Exception: PropertyNotFoundException: Could not find a setter and there Trainsient annotation on such method helped.
By specifying <transient name="isEmpty"/> you try to signal to the JPA provider that you have a transient property named isEmpty. Your property is actually named empty, not isEmpty, and the error message indicates that too (Foo#empty). Replace the corresponding XML tag with <transient name="empty"/>.

Unmarshalling with complex type

I'm having trouble unmarshalling XML that represents an invoice in this form:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soap:Body>
<Response xmlns="Lamp">
<Result>
<Title>The Title</Title>
<Lines>
<anyType xsi:type="InvoiceLine">
<Name>Name One</Name>
<Quantity>1.0000</Quantity>
</anyType>
<anyType xsi:type="InvoiceLine">
<Name>Name Two</Name>
<Quantity>2.0000</Quantity>
</anyType>
</Lines>
</Result>
</Response>
</soap:Body>
</soap:Envelope>
The Invoice class:
#XmlAccessorType(XmlAccessType.FIELD)
public class Invoice {
public String Title;
public List<InvoiceLine> Lines;
}
The InvoiceLine class:
#XmlAccessorType(XmlAccessType.FIELD)
public class InvoiceLine extends anyType {
public String Name;
public float quantity;
}
And a abstract class for anyType:
public abstract class anyType {}
This is the code I'm using to do the unmarshalling:
public static void main(String[] args) throws Exception {
InputStream is = new FileInputStream("input.xml");
XMLInputFactory xif = XMLInputFactory.newFactory();
XMLStreamReader xsr = xif.createXMLStreamReader(is);
xsr.nextTag();
while(!xsr.getLocalName().equals("Result")) {
xsr.nextTag();
}
JAXBContext jc = JAXBContext.newInstance(Invoice.class, InvoiceLine.class);
javax.xml.bind.Unmarshaller unmarshaller = jc.createUnmarshaller();
JAXBElement<Invoice> jb = unmarshaller.unmarshal(xsr, Invoice.class);
xsr.close();
System.out.println(jb.getValue());
}
The problem is the Lines list only contains 1 entry with Name=null and quantity=0.0.
-- Edit:
I've just tried adding XmlElement and XmlElementWrapper annotations to both classes, the only change is that the Lines list has no elements.
Modified Invoice:
#XmlAccessorType(XmlAccessType.FIELD)
public class Invoice {
#XmlElement(name = "Title")
public String Title;
#XmlElement(name = "anyType")
#XmlElementWrapper(name = "Lines")
public List<InvoiceLine> Lines;
}
Modified InvoiceLine:
#XmlAccessorType(XmlAccessType.FIELD)
public class InvoiceLine extends anyType {
#XmlElement(name = "Name")
public String Name;
#XmlElement(name = "Quantity")
public float Quantity;
}
-- Edit:
I've just tried making the attributes lower case, but still no luck.

Unmarshalling generic list with JAXB

I've a service that returns this XML:
<?xml version="1.0" encoding="UTF-8"?>
<response>
<status>success</status>
<result>
<project>
<id>id1</id>
<owner>owner1</owner>
</project>
<project>
<id>id2</id>
<owner>owner2</owner>
</project>
</result>
or
<?xml version="1.0" encoding="UTF-8"?>
<response>
<status>success</status>
<result>
<user>
<id>id1</id>
<name>name1</name>
</user>
<user>
<id>id2</id>
<name>name2</name>
</user>
</result>
I want to unmarshall the retrieved XML using these classes:
Result:
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Response<T> {
#XmlElement
protected String status;
#XmlElementWrapper(name = "result")
#XmlElement
protected List<T> result;
}
Project:
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Project {
#XmlElement
public String id;
#XmlElement
public String owner;
}
User:
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class User {
#XmlElement
public String id;
#XmlElement
public String name;
}
First not working solution
JAXBContext context = JAXBContext.newInstance(Response.class, Project.class, User.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
StreamSource source = new StreamSource(new File("responseProject.xml"));
Response<Project> responseProject = (Response<Project>)unmarshaller.unmarshal(source);
System.out.println(responseProject.getStatus());
for (Project project:responseProject.getResult()) System.out.println(project);
source = new StreamSource(new File("responseUser.xml"));
Response<User> responseUser = (Response<User>)unmarshaller.unmarshal(source);
System.out.println(responseUser.getStatus());
for (User user:responseUser.getResult()) System.out.println(user);
I get an empty list.
Second not working solution
Inspired by this article http://blog.bdoughan.com/2012/11/creating-generic-list-wrapper-in-jaxb.html I've modified the Response class:
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Response<T> {
#XmlElement
protected String status;
#XmlAnyElement(lax=true)
protected List<T> result;
}
And then tested it with this code:
Response<Project> responseProject = unmarshal(unmarshaller, Project.class, "responseProject.xml");
System.out.println(responseProject.getStatus());
for (Project project:responseProject.getResult()) System.out.println(project);
private static <T> Response<T> unmarshal(Unmarshaller unmarshaller, Class<T> clazz, String xmlLocation) throws JAXBException {
StreamSource xml = new StreamSource(xmlLocation);
#SuppressWarnings("unchecked")
Response<T> wrapper = (Response<T>) unmarshaller.unmarshal(xml, Response.class).getValue();
return wrapper;
}
And I get this exception reading the response list:
Exception in thread "main" java.lang.ClassCastException: com.sun.org.apache.xerces.internal.dom.ElementNSImpl cannot be cast to org.test.Project
Note: I can't modify the original XML. There are more types other than Project and User.
Thanks to Blaise Doughan and his article I've found the solution.
First we need the Wrapper class provided in the article:
#XmlRootElement
public class Wrapper<T> {
private List<T> items;
public Wrapper() {
items = new ArrayList<T>();
}
public Wrapper(List<T> items) {
this.items = items;
}
#XmlAnyElement(lax=true)
public List<T> getItems() {
return items;
}
}
Then I've modified the Response class in order to use it:
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Response<T> {
#XmlElement
protected String status;
#XmlElement
protected Wrapper<T> result;
...
public Response(String status, List<T> result) {
this.status = status;
this.result = new Wrapper<>(result);
}
...
public List<T> getResult() {
return result.getItems();
}
...
}
Finally the unmarshalling code:
JAXBContext context = JAXBContext.newInstance(Response.class, Project.class, User.class, Wrapper.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
StreamSource source = new StreamSource(new File("responseProject.xml"));
Response<Project> responseProject = (Response<Project>)unmarshaller.unmarshal(source);
System.out.println(responseProject.getStatus());
for (Project project:responseProject.getResult()) System.out.println(project);
source = new StreamSource(new File("responseUser.xml"));
Response<User> responseUser = (Response<User>)unmarshaller.unmarshal(source);
System.out.println(responseUser.getStatus());
for (User user:responseUser.getResult()) System.out.println(user);
I've added the Wrapper class to the context class list.
Alternatively you can add this annotation to the Response class:
#XmlSeeAlso({Project.class, User.class})
Using #XmlSeeAlso({Project.class, User.class}) on Response classes has the drawback of generating some garbage information on each entity in the list: xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="userAccount"
<resources>
<links>
<link>
<rel>self</rel>
<uri>http://localhost:8080/salonea-1.0/rest/user-accounts?offset=0&limit=2</uri>
</link>
<link>
<rel>prev</rel>
<uri></uri>
</link>
<link>
<rel>next</rel>
<uri>http://localhost:8080/salonea-1.0/rest/user-accounts?offset=2&limit=2</uri>
</link>
</links>
<collection>
<user-account
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="userAccount">
<accountType>user</accountType>
<activationCode>638f502a0e409348ccc2e36c24907f0</activationCode>
<email>michzio#hotmail.com</email>
<login>michzio</login>
<password>sAmPL3#e</password>
<registrationDate>2015-09-03T17:30:03+02:00</registrationDate>
<userId>1</userId>
</user-account>
<user-account
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="userAccount">
<accountType>user</accountType>
<activationCode>334bc79d142a291894bd71881e38a719</activationCode>
<email>alicja#krainaczarow.com</email>
<login>alicja</login>
<password>zAczka!00</password>
<registrationDate>2015-09-03T17:30:03+02:00</registrationDate>
<userId>2</userId>
</user-account>
</collection>
</resources>

Nested elements with JAXB where element holds attribute and element value at the same time

Environment: JAXB 2.1.2 with EclipseLink MOXy
Requirement:
I would like to get such an XML when marshalled:
<?xml version="1.0" encoding="UTF-8"?>
<root id="id123">
<email>test#gmail.com</email>
<address type="short">...</address>
</root>
I model this with these two classes:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name="root")
public class ClassA {
#XmlAttribute(name="id")
private String id = null;
#XmlElement(name="address")
private Address addr = new Address();
// and some getters setters
}
and
#XmlAccessorType(XmlAccessType.FIELD)
public class Address {
#XmlElement(name="address")
private String address = null;
#XmlAttribute(name="type")
private String type = null;
}
What I get is this, where address gets nested twice:
<?xml version="1.0" encoding="UTF-8"?>
<root id="id123">
<email>test#gmail.com</email>
<address type="short">
<address>...</address>
</address>
</root>
How can I remove one hierarchy?
You could do the following leveraging #XmlValue:
#XmlAccessorType(XmlAccessType.FIELD)
public class Address {
#XmlValue
private String address = null;
#XmlAttribute(name="type")
private String type = null;
}
For More Information
http://blog.bdoughan.com/2011/06/jaxb-and-complex-types-with-simple.html

Categories