Indeed you will need a custom converter for this as it is two nested collection which you do not want to show and those objects might have other child elements which would be serialized.
This is a case not directly covered by XStream, but easily fixed with a custom converter.
You can find all this in a git clone of your project which contains all those modifications. But as everything should be visible here, I subsequently explain the key portions to the question including some code examples.
I implemented such a converter for your project. The code doing the conversion is this:
@Override
public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
TestRow test = (TestRow)source;
for (TestArguments arg : test.getArguments()) {
for (ArgObject val : arg.getAllTestArguments()) {
writer.startNode(val.getKey());
writer.addAttribute("type", val.getType());
writer.setValue(val.getVal());
writer.endNode();
}
}
}
@Override
public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
TestArguments testargs = new TestArguments();
while (reader.hasMoreChildren()) {
reader.moveDown();
String typeval = reader.getAttribute("type");
if (typeval.isEmpty()) {
typeval = "null";
}
testargs.getAllTestArguments().add(new ArgObject(reader.getNodeName(), typeval, reader.getValue()));
reader.moveUp();
}
TestRow result = new TestRow(testargs);
return result;
}
This will serialize all ArgObjects to xml with the flat node structure you defined in your ArgConverter
. The deserialization creates the object back from this data.
You had two bugs in your source code which prevented deserialization:
- XStream deserialization does not recognize all alias Annotations. It had problems with your root element
SuiteData
(aliased to suite). For this I added a aliad to the XStream object like this xStream.alias("suite", SuiteData.class);
in your XMLDataHelper
.
- If you create a
TestArguments
instance with a default constructor (as you'll have to through deserialization), you call reset which assigns your argsWrapper
member to null which then makes adding arguments quite impossible. I fixed that be newly initializing that member variable in the reset method (argsWrapper = new ArrayList<ArgObject>();
).
As far as I understand your code this works as expected for serialization / deserialization. I wrote a small test program to force this process in each way and it seems to produce the same result:
public class XMLDataHelperTest {
public static void main(String[] args) {
File file = new File(System.getProperty("user.dir"), "test.xml");
if (file.isFile()) {
assertTrue(file.delete());
}
// write it once
XMLDataHelper helper = new XMLDataHelper(file.getAbsolutePath());
// read it once
helper = new XMLDataHelper(file.getAbsolutePath());
System.out.println(file);
}
}