Codebase list libxstream-java / b8a70739-af6c-495a-8f08-8b3abe9e9e25/main xstream-distribution / src / content / graphs.html
b8a70739-af6c-495a-8f08-8b3abe9e9e25/main

Tree @b8a70739-af6c-495a-8f08-8b3abe9e9e25/main (Download .tar.gz)

graphs.html @b8a70739-af6c-495a-8f08-8b3abe9e9e25/mainraw · history · blame

<html>
<!--
 Copyright (C) 2006 Joe Walnes.
 Copyright (C) 2006, 2007, 2009 XStream committers.
 All rights reserved.
 
 The software in this package is published under the terms of the BSD
 style license a copy of which has been included with this distribution in
 the LICENSE.txt file.
 
 Created on 03. April 2006 by Guilherme Silveira
 -->
  <head>
    <title>Object references</title>
  </head>

  <body>

    <!-- ...................................................... -->
    <h2 id="references">How does XStream deals with duplicate and circular references?</h2>
    <p>It depends on XStream's mode, the default is uses XPath to allow serialized objects to be treated as graphs instead of simple trees (typical XML usage).</p>
    
    <p>Sometimes it's not desirable to work this way, let's take a look in a simple example in order to switch between XStream's modes and see what its capable of.</p>
    <p>We start with a simple compact-disc class, with id and a bonus cd fields:</p>
    
<div class="Source Java"><pre>package com.thoughtworks.xstream;
public class Cd {
	private String id;

	private Cd bonusCd;

	Cd(String id, Cd bonusCd) {
		this.id = id;
		this.bonusCd = bonusCd;
	}

	Cd(String id) {
		this.id = id;
	}

	public String getId() {
		return id;
	}

	public Cd getBonusCd() {
		return bonusCd;
	}
}</pre></div>

	<p>And let's create an order with the same cd twice and the order itself, so we can simulate
 two references to the same object and a back-reference.</p>
 
<div class="Source Java"><pre>Cd bj = new Cd("basement_jaxx_singles");
		
List order = new ArrayList();
// adds the same cd twice (two references to the same object)
order.add(bj);
order.add(bj);

// adds itself (cycle)
order.add(order);

XStream xstream = new XStream();
xstream.alias("cd", Cd.class);
System.out.println(xstream.toXML(order));
</pre></div>

	<p>If we execute the above code, XStream's uses its <b>default mode</b> called XPATH_RELATIVE_REFERENCES
	based on the W3C XPath specification. Cross and back references are treated in a way that it's (almost) human
readable:</p>

<div class="Source Java"><pre>
&lt;list&gt;
  &lt;cd&gt;
    &lt;id&gt;maria rita&lt;/id&gt;
  &lt;/cd&gt;
  &lt;cd&gt;
    &lt;id&gt;basement_jaxx_singles&lt;/id&gt;
  &lt;/cd&gt;
  &lt;cd reference="../cd[2]"/&gt;
  &lt;list reference=".."/&gt;
&lt;/list&gt;
</pre></div>

	<p>The second reference to the Basement Jaxx cd was serialized as "../cd[2]" while the order inside
itself used the ".." path. The XPath Relative mode allows any type of graphs to be used as both cross and
back-references are supported.</p>

	<p>In order to make use of the XPath Relative mode one can implicitly call:</p>
	
<div class="Source Java"><pre>
xstream.setMode(XStream.XPATH_RELATIVE_REFERENCES);
</pre></div>

    <!-- ...................................................... -->
    <h2 id="rel-abs">Relative x Absolute</h2>
    
    <p>There is an absolute mode which is easy to use and understand. It works
using the same XPath specification and also supports all types of graphs.</p>

<div class="Source Java"><pre>
xstream.setMode(XStream.XPATH_ABSOLUTE_REFERENCES);
</pre></div>

	<p>The changes in the resulting xml is a little more 'clutter':</p>

<div class="Source Java"><pre>
&lt;list&gt;
  &lt;cd&gt;
    &lt;id&gt;maria rita&lt;/id&gt;
  &lt;/cd&gt;
  &lt;cd&gt;
    &lt;id&gt;basement_jaxx_singles&lt;/id&gt;
  &lt;/cd&gt;
  &lt;cd reference="/list/cd[2]"/&gt;
  &lt;list reference="/list"/&gt;
&lt;/list&gt;
</pre></div>


    <!-- ...................................................... -->
    <h2 id="single-node">Single Node Selectors</h2>

	<p>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:</p>

<div class="Source Java"><pre>
xstream.setMode(XStream.SINGLE_NODE_XPATH_ABSOLUTE_REFERENCES);
xstream.setMode(XStream.SINGLE_NODE_XPATH_RELATIVE_REFERENCES);
</pre></div>

	<p>The changes in the resulting xml is even more 'clutter':</p>

<div class="Source Java"><pre>
&lt;list&gt;
  &lt;cd&gt;
    &lt;id&gt;maria rita&lt;/id&gt;
  &lt;/cd&gt;
  &lt;cd&gt;
    &lt;id&gt;basement_jaxx_singles&lt;/id&gt;
  &lt;/cd&gt;
  &lt;cd reference="/list[1]/cd[2]"/&gt;
  &lt;list reference="/list[1]"/&gt;
&lt;/list&gt;
</pre></div>

	<p>For XStream is the notation with the single node selectors absolutely equivalent to the
	one without. These two notations are completely transparent at deserialization time.</p>

    <!-- ...................................................... -->
    <h2 id="ids">Id mode</h2>
    
	<p>Both modes displayed until now are not so easy to write by hand. XStream has another
	mode which makes it is easier to read/write by a human being:</p>

<div class="Source Java"><pre>
xstream.setMode(XStream.ID_REFERENCES);
</pre></div>

	<p>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.</p>

	<p>In our example, the list has id 1, the Maria Rita cd 2, and the Basement Jaxx 3. Therefore
	the cross-reference to our cd should contain a reference attribute to object number 2 and
	the back-reference to our order a reference to object 1. The result is:</p>

<div class="Source Java"><pre>
&lt;list id="1"&gt;
  &lt;cd id="2"&gt;
    &lt;id&gt;maria rita&lt;/id&gt;
  &lt;/cd&gt;
  &lt;cd id="3"&gt;
    &lt;id&gt;basement_jaxx_singles&lt;/id&gt;
  &lt;/cd&gt;
  &lt;cd reference="3"/&gt;
  &lt;list reference="1"/&gt;
&lt;/list&gt;
</pre></div>

    <!-- ...................................................... -->
    <h2>No references</h2>
    
	<p>For some uses of XStream we do not desire any kind of back or cross references like a graph, but a simple
	tree. The most famous example is when using XStream to generate XML for B2B services.</p>

	<p>In such scenarios it's impossible to represent a graph cycle (remember: no tree contains such structure), therefore
	we have to remove the last <b>add</b> call from our example:</p>
	
<div class="Source Java"><pre>Cd bj = new Cd("basement_jaxx_singles");
		
List order = new ArrayList();
// adds the same cd twice (two references to the same object)
order.add(bj);
order.add(bj);

XStream xstream = new XStream();
xstream.alias("cd", Cd.class);
System.out.println(xstream.toXML(order));
</pre></div>

	<p>Now if we add the NO_REFERENCES option, every reference shall be completed serialized.</p>

<div class="Source Java"><pre>
xstream.setMode(XStream.NO_REFERENCES);
</pre></div>

	<p>The result are three references:</p>

<div class="Source Java"><pre>
&lt;list&gt;
  &lt;cd&gt;
    &lt;id&gt;maria rita&lt;/id&gt;
  &lt;/cd&gt;
  &lt;cd&gt;
    &lt;id&gt;basement_jaxx_singles&lt;/id&gt;
  &lt;/cd&gt;
  &lt;cd&gt;
    &lt;id&gt;basement_jaxx_singles&lt;/id&gt;
  &lt;/cd&gt;
&lt;/list&gt;
</pre></div>

	<p>After reading from the above XML, you will get three <b>different</b> Cd instances.</p>
	
	<p>Remember: it's impossible to support back-references (cycles) with NO_REFERENCES mode activated therefore
	a CircularReferenceException is thrown if you ever try to do so.</p>
	
  </body>
</html>