I am having difficulty adding an attribute to a child element for writing an XML file. The challenge, for me at least, is that the POJO that the element is mapped to is associated with a parent element. I want the XML output to look like this:
<TXLife version="2.42.00" xmlns="http://ACORD.org/Standards/Life/2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<TXLifeRequest>
<TransRefGUID>906D67C1-CC4D-11CF-91FB-444554540000</TransRefGUID>
<TransType tc="1203"></TransType>
<TransExeDate>2020-01-06</TransExeDate>
<TransExeTime>09:30:00</TransExeTime>
...multiple other parent and child elements..
</TXLifeRequest>
</TXLife>
It's the TransType element in which I need to add the attribute (as shown above).
The POJOS:
@XStreamAlias("TXLife")
public class TXLife {
@XStreamAsAttribute
private String version;
@XStreamAsAttribute
final String xmlns = "http://ACORD.org/Standards/Life/2";
@XStreamAsAttribute
@XStreamAlias("xmlns:xsi")
final String xlink="http://www.w3.org/2001/XMLSchema-instance";
@XStreamImplicit
private List<TXLifeRequest> transListings = new ArrayList<TXLifeRequest>();
public TXLife() {
super();
}
...getters and setters
@XStreamAlias("TXLifeRequest")
public class TXLifeRequest {
@XStreamAlias("TransRefGUID")
private String transRefGUID;
@XStreamAlias("TransType")
private String transType;
@XStreamAlias("TransExeDate")
private String transExeDate;
@XStreamAlias("TransExeTime")
private String transExeTime;
public TXLifeRequest(String transRefGUID, String transType, String transExeDate, String transExeTime) {
this.transRefGUID = transRefGUID;
this.transType = transType;
this.transExeDate = transExeDate;
this.transExeTime = transExeTime;
}
...getters and setters
Converter:
public class TransTypeAttributeConverter implements Converter {
@Override
public void marshal(Object o, HierarchicalStreamWriter hierarchicalStreamWriter, MarshallingContext marshallingContext) {
TXLifeRequest txLifeRequest = (TXLifeRequest) o;
hierarchicalStreamWriter.addAttribute("tc", "1203");
hierarchicalStreamWriter.setValue("");
}
@Override
public Object unmarshal(HierarchicalStreamReader hierarchicalStreamReader, UnmarshallingContext unmarshallingContext) {
return null;
}
@Override
public boolean canConvert(Class type) {
return type.equals(TXLifeRequest.class);
}
}
Test class:
public class TestXMLOutput {
public static void main(String[] args) throws UnsupportedEncodingException {
TestXMLOutput testXMLOutput = new TestXMLOutput();
TXLife txLife = new TXLife();
txLife.setVersion("2.42.00");
txLife.add(new TXLifeRequest("906D67C1-CC4D-11CF-91FB-444554540000", "",
"2020-01-06", "09:30:00"));
testXMLOutput.testConvertAndWriteXMLToFile(txLife);
}
public void testConvertAndWriteXMLToFile(TXLife txLife) throws UnsupportedEncodingException {
XStream xstream = new XStream(new StaxDriver());
xstream.processAnnotations(TXLife.class);
xstream.alias("TXLife", TXLife.class);
xstream.processAnnotations(TXLifeRequest.class);
xstream.alias("TXLifeRequest", TXLifeRequest.class);
BufferedOutputStream bos = null;
try {
bos = new BufferedOutputStream(new FileOutputStream("CITS_BoB/src/test/java/txlife.xml"));
} catch (IOException e) {
System.out.println("IOException Occurred: " + e.getMessage());
}
xstream.addImplicitCollection(TXLife.class, "transListings");
//xstream.registerConverter(new TransTypeAttributeConverter());
xstream.marshal(txLife, new PrettyPrintWriter(
new OutputStreamWriter(bos, StandardCharsets.UTF_8)));
}
}
I have found that running both the xstream.addImplicitCollection(...) and xstream.registerConverter(...) in the test class produces the following XML output:
<TXLife version="2.42.00" xmlns="http://ACORD.org/Standards/Life/2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<TXLifeRequest tc="1203"></TXLifeRequest>
</TXLife>
I am sure I have misunderstood, or missed altogether, how to properly use xstream to do this sort of task. In any examples I have found online the element to which the attribute is added is mapped to a class, whereas in my case the element I want to add the attribute to is itself in a class that is mapped to a "parent" element. I have gone through the xstream website but haven't found any example directly related to my goal here. JAXB is unfortunately not an option as I am using openjdk 12 which does not support that. I don't know if there is an XML document writer built into openjdk 12 (I am still new to that version). I guess what I can't figure out is how to somehow "associate" the specific child element in the TXLifeRequest POJO with the attribute I want added to it. Please excuse my incorrect use of code, for one, the string literals added in the hierarchicalStreamWriter.addAttribute("tc", "1203"); statement in the TransTypeAttributeConverter I am sure are in the wrong context or place. If anyone can shed some light on this it would be greatly appreciated. Thank you!
Sorry, I should also add that other options I have considered is to write POJOs for each element (which I realize is likely extreme and inefficient), or, to map the child element in the POJO to an inner class such that it in effect becomes it's own parent element.
I ended up using the java DOM parser as a solution, which allowed me to set the attribute directly on the element TransType. If by chance someone does know how to resolve this issue in XStream I would still be interested to know. Cheers.