Interface GraphCloneable


public interface GraphCloneable
Implemented by objects in an object graph that support graph cloning, i.e., deep copies without duplicates and preserving reference topology.

Graph cloning creates a copy of an object graph that, like a normal deep copy, contains no references to objects in the original object graph (except for immutables), but in addition, each GraphCloneable object is only copied once. As a result the copy graph has the same reference topology as the original graph (with respect to all the GraphCloneables). In particular, reference cycles among GraphCloneables are preserved and do not cause infinite loops.

Graph cloning operates similar to a deep copy operation, except that graph cloning uses a GraphCloneRegistry to keep track of new objects as they are created. When each object's GraphCloneable references are copied, the GraphCloneRegistry is used to check whether the referred-to objects have already been copied, and if so, the existing copy is used. This requires that implementations register their clones prior to recursing on any GraphCloneable fields.

The net effect is equivalent to serializing and then deserializing the entire object graph, but without the overhead, losing transient values, and other issues.

Here is an example of a class properly implementing this interface:

  // We implement Cloneable so super.clone() will work
  public class Person implements Cloneable, GraphCloneable {

      // Regular fields
      private int age;
      private String lastName;
      private String firstName;
      private List<String> nicknames = new ArrayList<String>();

      // GraphCloneable fields - values may be null and/or even refer back to me
      private Person spouse;
      private List<Person> friends = new ArrayList<Person>();

      // Getters & setters go here...

      // Our implementation of the GraphCloneable interface
      @Override
      public void createGraphClone(GraphCloneRegistry registry) throws CloneNotSupportedException {

          // Create clone and register it with the registry
          final Person clone = (Person)super.clone();         // this copies all of the simple fields
          registry.setGraphClone(clone);                      // let the registry know who our clone is

          // Deep copy any non-GraphCloneable fields not already handled by super.clone()
          clone.nicknames = new ArrayList<String>(this.nicknames);

          // Now copy GraphCloneable fields using registry.getGraphClone()
          clone.spouse = registry.getGraphClone(this.spouse);
          clone.friends = new ArrayList<Person>(this.friends.size());
          for (Person friend : this.friends)
              clone.friends.add(registry.getGraphClone(friend));
      }
  }
  

To graph clone any object graph rooted at root, you would do this:

      new GraphCloneRegistry().getGraphClone(root);
  
See Also: