JAXB: How to marshal objects in lists?
Perhaps a stupid question: I have a List
of type <Data>
which I want to marshal into a XML file. This is my class Database
containing an ArrayList
...
@XmlRootElement
public class Database
{
List<Data> records = new ArrayList<Data>();
public List<Data> getRecords() { return records; }
public void setRecords(List<Data> records) { this.records = records; }
}
...and this is class Data:
// @XmlRootElement
public class Data
{
String name;
String address;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getAddress() { return address; }
public void setAddress(String address) { this.address = address; }
}
Using the following test class...
public class Test
{
public static void main(String args[]) throws Exception
{
Data data1 = new Data();
data1.setName("Peter");
data1.setAddress("Cologne");
Data data2 = new Data();
data2.setName("Mary");
data2.setAddress("Hamburg");
Database database = new Database();
database.getRecords().add(data1);
database.getRecords().add(data2);
JAXBContext context = JAXBContext.newInstance(Database.class);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(database, new FileWriter("test.xml"));
}
}
...I got the result:
<database>
<records>
<address>Cologne</address>
<name>Peter</name>
</records>
<records>
<address>Hamburg</address>
<name>Mary</name>
</records>
</database>
But that's not what I was expecting, i.e. all tags for <Data>
objects are missing. I am looking for a way to export the data in the following structure, but I don't know how to achieve this:
<database>
<records>
<data>
<address>Cologne</address>
<name>Peter</name>
</data>
<data>
<address>Hamburg</address>
<name>Mary</name>
</data>
</records>
</database>
One additional question: if I want to deal with the problem without using @XmlElementWrapper
and @XmlElement
annotations, I can introduce an intermediary class
public class Records
{
List<Data> data = new ArrayList<Data>();
public List<Data> getData() { return data; }
public void setData(List<Data> data) { this.data = data; }
}
used by the modified base class
@XmlRootElement
public class Database
{
Records records = new Records();
public Records getRecords() { return records; }
public void setRecords(Records records) { this.records = records; }
}
in a slightly modified Test
class:
...
Database database = new Database();
database.getRecords().getData().add(data1);
database.getRecords().getData().add(data2);
...
The result also is:
<database>
<records>
<data>
<address>Cologne</address>
<name>Peter</name>
</data>
<data>
<address>Hamburg</address>
<name>Mary</name>
</data>
</records>
</database>
Is this the recommended way to create a Java class structure according to the XML file structure above?
On the records property add:
@XmlElementWrapper(name="records")
@XmlElement(name="data")
For more information on JAXB and collection properties see:
- JAXB & Collection Properties
This is in response to your second question disquised an answer:
- JAXB: How to marshal objects in lists?
Both approaches will generate the same XML. My recommendation is go with the model that is best for your application. For me that is generally using @XmlElementWrapper/@XmlElement. Since "records" is just there to organize the "data" elements it doesn't really deserve its own class.
I lead the MOXy JAXB implementation and we offer an XPath-based mapping extension to go beyond what is capable with @XmlElementWrapper:
- http://bdoughan.blogspot.com/2010/07/xpath-based-mapping.html
- http://bdoughan.blogspot.com/2010/09/xpath-based-mapping-geocode-example.html
In response to your second question:
Is this the recommended way to create a Java class structure
according to the XML file structure above?
Technically speaking, introducing an extra Records
class to solve your JAXB issue is unnecessary and redundant work, because JAXB does not need it. The
@XmlElementWrapper
and @XmlElement
name
property have been designed to solve your issue.
From your comments to Blaise's answer, I maintain a tutorial with operational examples explaining how do deal with generic classes such as List, etc.. when unmarshalling.