Knowledge Base

An archive of my personal knowledge base.

XStream - Object references

Cristian Sulea

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>

Share on Twitter