How to use references in XML and Castor Intended Audience Prerequisites Example: A Simple Graph Castor and Non-Hierarchical Object Models Working with Identities and References in Castor XML References
Intended Audience
Anyone who wants to model non-hierarchical object relations in XML using
Castor.
This document helps people to get familiar with the basic concepts
and discusses some implementation details.
Prerequisites
None.
Example: A Simple Graph
As a motivating example for this HOW-To, consider a graph consisting of
nodes and branches. For this example we're going to take a node-centric
view of the graph, so each node is a Java object that contains a list of
other nodes it is connected to (thus modeling the branches). The node
class might look like:
import java.util.List;
public class Node
{
protected int nodeNum;
protected List siblings;
/* ... business fields ... */
public Node() {};
public Node( int nodeNum, List siblings ) {
this.nodeNum = nodeNum;
this.siblings = siblings;
}
public int getNodeNum() { return nodeNum; }
public void setNodeNum( int nodeNum ) { this.nodeNum = nodeNum; }
public List getSiblings() { return siblings; }
public void setSiblings( List siblings ) { this.siblings = siblings; }
/* ... business logic ... */
} |
|
Castor and Non-Hierarchical Object Models
The default marshalling behavior in Castor is to create a new element for
each object contained by the object being marshalled. For a lot of
applications this is acceptable as the Java object model being marshalled
is hierarchical. The same goes for unmarshalling but in the opposite
direction; i.e. a new object is created for each element in the XML.
Now consider the graph example above. If that model is marshalled or
unmarshalled with the default behavior, all the relations between the
nodes will be broken. Even using a mapping file like the one below won't
help.
<?xml version="1.0"?>
<!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN"
"http://castor.org/mapping.dtd">
<mapping>
<class name="Node">
<map-to xml="node" />
<field name="nodeNum" type="integer">
<bind-xml name="node-num" node="attribute" />
</field>
<field name="siblings" type="Node" collection="collection">
<bind-xml name="sibling" />
</field>
</class>
</mapping> |
|
After unmarshalling each Node object will contain a list of
siblings, but those siblings will be specific to that Node. They
may be populated with the right data (nodeNum etc.) to begin
with, but any changes won't propogate to the other nodes.
Working with Identities and References in Castor XML
Enter identities and references -- using a mapping file, it is possible to
tell Castor how to identify specific instances of a class and when to
simply reference an object rather than create a new one. In the example
above, assume nodeNum is unique across all nodes and thus can be
used to identify each node individually. Once an identity is defined
it is possible to instruct Castor to only reference instances of the class
rather than creating new objects.
For the graph example above, the correct mapping file would look like
this:
<?xml version="1.0"?>
<!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN"
"http://castor.org/mapping.dtd">
<mapping>
<class name="Node" identity="nodeNum">
<map-to xml="node" />
<field name="nodeNum" type="integer">
<bind-xml name="node-num" node="attribute" />
</field>
<field name="siblings" type="Node" collection="collection">
<bind-xml name="sibling" reference="true" />
</field>
</class>
</mapping> |
|
The key attributes in the mapping file are identity in the
class element, and reference in the bind-xml
element. When reference is set to true, Castor knows to create
only a reference to the object rather than a full object. This
accomplishes two things: first, it reduces the size of the XML file
created during marshalling because each object is completely written out
only once, and two, on unmarshal, the objects will maintain the correct
relations to each other.
Marshalling an ArrayList of these Node objects then looks like:
<?xml version="1.0" encoding="UTF-8"?>
<array-list>
<node node-num="1">
<!-- Other fields get marshalled here -->
<sibling>2</sibling>
<sibling>3</sibling>
</nod>
<node node-num="2">
<!-- Other fields get marshalled here -->
<sibling>1</sibling>
<sibling>3</sibling>
</nod>
<node node-num="3">
<!-- Other fields get marshalled here -->
<sibling>1</sibling>
<sibling>2</sibling>
</nod>
</array-list> |
|
References
|