XStream - Object references
XStream is a simple java library to serialize objects to XML and back again.
But how does XStream deals with duplicate and circular references? By default is using XPath to allow serialized objects to be treated as graphs instead of simple trees (typical XML usage).
The objects:
public class Contact {
private String name;
private List<Address> addresses;
public Contact(String name, Address... addresses) {
this.name = name;
this.addresses = new ArrayList<Address>(Arrays.asList(addresses));
}
public Contact(String name, List<Address> addresses) {
this.name = name;
this.addresses = addresses;
}
// ... other constructors and methods
}
public class Address {
private String street;
private String city;
public Address(String street, String city) {
this.street = street;
this.city = city;
}
// ... other constructors and methods
}
The test code:
public static void main(String[] args) {
XStream xStream = new XStream(new DomDriver());
xStream.alias("contact", Contact.class);
xStream.alias("address", Address.class);
Address address = new Address("My Street", "Bucharest");
Contact contact = new Contact("Cristian Sulea", address, address);
xStream.toXML(contact, System.out);
}
XPath Relative
If we execute the test code, XStream’s uses its default mode called XPATH_RELATIVE_REFERENCES
based on the W3C XPath specification:
<contact>
<name>Cristian Sulea</name>
<addresses>
<address>
<street>My Street</street>
<city>Bucharest</city>
</address>
<address reference="../address" />
</addresses>
</contact>
The explicit call is:
xStream.setMode(XStream.XPATH_RELATIVE_REFERENCES);
XPath Absolute
There is also an absolute mode which is easy to use and understand:
xStream.setMode(XStream.XPATH_ABSOLUTE_REFERENCES);
In this case the resulting XML is:
<contact>
<name>Cristian Sulea</name>
<addresses>
<address>
<street>My Street</street>
<city>Bucharest</city>
</address>
<address reference="/contact/addresses/address"/>
</addresses>
</contact>
Single Node Selectors
In some cases where the XML is used later on or is generated by someone else, the XPath selectors can be forced to select always a single node instead of a node list where the first element is taken.
Therefore two more modes exist:
xStream.setMode(XStream.SINGLE_NODE_XPATH_ABSOLUTE_REFERENCES);
with resulting XML
<contact>
<name>Cristian Sulea</name>
<addresses>
<address>
<street>My Street</street>
<city>Bucharest</city>
</address>
<address reference="/contact[1]/addresses[1]/address[1]" />
</addresses>
</contact>
and
xStream.setMode(XStream.SINGLE_NODE_XPATH_RELATIVE_REFERENCES);
with resulting XML
<contact>
<name>Cristian Sulea</name>
<addresses>
<address>
<street>My Street</street>
<city>Bucharest</city>
</address>
<address reference="../address[1]" />
</addresses>
</contact>
Id Mode
XStream has another mode which makes it is easier to read/write by a human being:
xStream.setMode(XStream.SINGLE_NODE_XPATH_RELATIVE_REFERENCES);
The result is a XML which generates an id
attribute for each new object marshaled, and whenever it finds back or cross-references, it uses a reference
attribute to so it doesn’t copy the entire object:
<contact id="1">
<name>Cristian Sulea</name>
<addresses id="2">
<address id="3">
<street>My Street</street>
<city>Bucharest</city>
</address>
<address reference="3" />
</addresses>
</contact>
NO References
For some uses of XStream we do not desire any kind of back or cross references like a graph, but a simple tree. Remember that in such scenarios it’s impossible to represent a graph cycle (no tree contains such structure).
xStream.setMode(XStream.NO_REFERENCES);
In the resulting XML every reference shall be serialized:
<contact>
<name>Cristian Sulea</name>
<addresses>
<address>
<street>My Street</street>
<city>Bucharest</city>
</address>
<address>
<street>My Street</street>
<city>Bucharest</city>
</address>
</addresses>
</contact>
Categories & Tags
Related
Share