Let's say we have the following XML file:
<?xml version="1.0" encoding="UTF-8" ?>
<car>
<name>Speedy VW Golf</name>
<tires>
<tire>
<value>Michelin FL</value>
</tire>
<tire>
<value>Michelin FR</value>
</tire>
<tire>
<value>Michelin BL</value>
</tire>
<tire>
<value>Michelin BR</value>
</tire>
</tires>
<component componentId="compId", serialId="lalal">
<frame frameId="1234-56789-0" vendor="Steel MC">
<item vendorName="Foo" country="Italy"/>
<item vendorName="Bar" country="Germany"/>
<item vendorName="Foobar" country="China"/>
</frame>
</component>
</car>
How can I map all item
children? The following Java code:
package com.acme.carsample;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import java.io.File;
import java.nio.file.Files;
import java.util.List;
public class CarReader {
@JsonIgnoreProperties(ignoreUnknown = true)
public static class Car {
private String name;
private List<Tire> tires;
private Component component;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Tire> getTires() {
return tires;
}
public void setTires(List<Tire> tires) {
this.tires = tires;
}
public Component getComponent() {
return component;
}
public void setComponent(Component component) {
this.component = component;
}
}
@JsonIgnoreProperties(ignoreUnknown = true)
public static class Tire {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
@JsonIgnoreProperties(ignoreUnknown = true)
public static class Component {
private Frame frame;
public Frame getFrame() {
return frame;
}
public void setFrame(Frame frame) {
this.frame = frame;
}
}
@JsonIgnoreProperties(ignoreUnknown = true)
public static class Frame {
@JacksonXmlProperty(isAttribute = true)
private String frameId;
@JacksonXmlProperty(isAttribute = true)
private String vendor;
@JacksonXmlElementWrapper(useWrapping = false)
private List<Item> items;
public String getFrameId() {
return frameId;
}
public void setFrameId(String frameId) {
this.frameId = frameId;
}
public String getVendor() {
return vendor;
}
public void setVendor(String vendor) {
this.vendor = vendor;
}
public List<Item> getItems() {
return items;
}
public void setItems(List<Item> items) {
this.items = items;
}
}
@JsonIgnoreProperties(ignoreUnknown = true)
@JacksonXmlRootElement(localName = "item")
public static class Item {
@JacksonXmlProperty(isAttribute = true)
private String vendorName;
@JacksonXmlProperty(isAttribute = true)
private String country;
public String getVendorName() {
return vendorName;
}
public void setVendorName(String vendorName) {
this.vendorName = vendorName;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
}
public static void main(String[] arguments) {
try {
// Deserialize the car object (XML to Java)
String data = new String(Files.readAllBytes(new File("Car.xml").toPath()));
XmlMapper xmlMapper = new XmlMapper();
Car car = xmlMapper.readValue(data, Car.class);
// Serialize the car object (Java to json)
ObjectMapper objectMapper = new ObjectMapper();
data = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(car);
System.out.println(data);
} catch (Exception exception) {
System.err.println("An error occurred: " + exception.getMessage());
}
}
}
Results in the following JSON output (The item
children attributes are not mapped as list, but are instead null
:
{
"name" : "Speedy VW Golf",
"tires" : [ {
"value" : "Michelin FL"
}, {
"value" : "Michelin FR"
}, {
"value" : "Michelin BL"
}, {
"value" : "Michelin BR"
} ],
"component" : {
"frame" : {
"frameId" : "1234-56789-0",
"vendor" : "Steel MC",
"items" : null
}
}
}
The solution is to move the @JacksonXmlRootElement
class annotation from the Item
class to the field variable items
in Frame
:
@JacksonXmlProperty(localName = "item")
@JacksonXmlElementWrapper(useWrapping = false)
private List<Item> items;
Afterwards the child item are properly read.