I have some strange xml I am trying deserialize to java objects
<Operator>
<Parameter Key="a" Value="1"/>
<Parameter Key="b" Value="2"/>
<Parameter Key="c" Value="3"/>
<StorageParameters Key="x" Value="***"/>
<Parameter Key="d" Value="4"/>
</Operator>
I need to collect only the Parameter nodes as a list. I have written my java classes as follows
@JsonIgnoreProperties(ignoreUnknown = true)
public class Operator {
@JacksonXmlProperty(localName="Parameter")
@JacksonXmlElementWrapper(useWrapping = false)
private List<Parameter> parameters;
public Operator() {
this.parameters = List.of();
}
public List<Parameter> getParameters() {
return parameters;
}
public void setParameters(List<Parameter> parameters) {
this.parameters = parameters;
}
}
public class Parameter {
private String Key;
private String Value;
public Parameter() {
Key = "";
Value = " ";
}
public String getKey() {
return Key;
}
public void setKey(String key) {
Key = key;
}
public String getValue() { return Value; }
public void setValue(String value) {
Value = value;
}
}
// Driver
JacksonXmlModule module = new JacksonXmlModule();
XmlMapper mapper = new XmlMapper(module);
Operator bean = mapper.readValue(xmlText, classOf[Operator])
When I run this the only value returned by the parameters list is the last Parameter entry with Key="d" and Value="4".
Is this expected behavior? Is there any annotation I can use to get all the Parameter Key/Value pairs?
Thanks!
The problem here is the presence of the <StorageParameters Key="x" Value="***"/>
tag: the jackson library expects in a list to deserialize only the presence of n <Parameter/>
equal tags but instead finds a different tag and consequently decides to interpret the list as distinct properties, so the last <Parameter Key="d" Value="4"/>
overwrites the previous values of the Parameter
property and then the strange behaviour (the other StorageParameters
is ignored cause the JsonIgnoreProperties(ignoreUnknown = true)
annotation in the Operator
class).
To avoid this behaviour you can delete the undesired StorageParameters
and deserialize your xml parsing the old xml and creating a new one without the undesired tag like below :
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(new FileInputStream(xml));
Node node = doc.getElementsByTagName("StorageParameters").item(0);
node.getParentNode().removeChild(node);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer t = tf.newTransformer();
StringWriter writer = new StringWriter();
t.transform(new DOMSource(doc), new StreamResult(writer));
String result = writer.getBuffer().toString();
Operator value = mapper.readValue(result, Operator.class);
You have to use the JacksonXmlProperty(isAttribute = true)
annotation in your Parameter
to indicate that values are attributes:
@Data
public class Parameter {
@JacksonXmlProperty(isAttribute = true)
private String Key;
@JacksonXmlProperty(isAttribute = true)
private String Value;
}
@Data
public class Operator {
@JacksonXmlProperty(localName = "Parameter")
@JacksonXmlElementWrapper(useWrapping = false)
private List<Parameter> parameters;
}