Class Cloner

java.lang.Object
com.jme3.util.clone.Cloner

public class Cloner extends Object
A deep clone utility that provides similar object-graph-preserving qualities to typical serialization schemes. An internal registry of cloned objects is kept to be used by other objects in the deep clone process that implement JmeCloneable.

By default, objects that do not implement JmeCloneable will be treated like normal Java Cloneable objects. If the object does not implement the JmeCloneable or the regular JDK Cloneable interfaces AND has no special handling defined then an IllegalArgumentException will be thrown.

Enhanced object cloning is done in a two step process. First, the object is cloned using the normal Java clone() method and stored in the clone registry. After that, if it implements JmeCloneable then its cloneFields() method is called to deep clone any of the fields. This two step process has a few benefits. First, it means that objects can easily have a regular shallow clone implementation just like any normal Java objects. Second, the deep cloning of fields happens after creation which means that the clone is available to future field cloning to resolve circular references.

Similar to Java serialization, the handling of specific object types can be customized. This allows certain objects to be cloned gracefully even if they aren't normally Cloneable. This can also be used as a sort of filter to keep certain types of objects from being cloned. (For example, adding the IdentityCloneFunction for Mesh.class would cause all mesh instances to be shared with the original object graph.)

By default, the Cloner registers several default clone functions as follows:

  • java.util.ArrayList: ListCloneFunction
  • java.util.LinkedList: ListCloneFunction
  • java.util.concurrent.CopyOnWriteArrayList: ListCloneFunction
  • java.util.Vector: ListCloneFunction
  • java.util.Stack: ListCloneFunction
  • com.jme3.util.SafeArrayList: ListCloneFunction

Usage:

  // Example 1: using an instantiated, reusable cloner.
  Cloner cloner = new Cloner();
  Foo fooClone = cloner.clone(foo);
  cloner.clearIndex(); // prepare it for reuse
  Foo fooClone2 = cloner.clone(foo);

  // Example 2: using the utility method that self-instantiates a temporary cloner.
  Foo fooClone = Cloner.deepClone(foo);

  
  • Constructor Summary

    Constructors
    Constructor
    Description
    Creates a new cloner with only default clone functions and an empty object index.
  • Method Summary

    Modifier and Type
    Method
    Description
    protected <T> T
    arrayClone(T object)
    Clones a primitive array by coping it and clones an object array by coping it and then running each of its values through Cloner.clone().
    void
    Clears the object index allowing the cloner to be reused for a brand-new cloning operation.
    <T> T
    clone(T object)
    Deeps clones the specified object, reusing previous clones when possible.
    <T> T
    clone(T object, boolean useFunctions)
    Deeps clones the specified object, reusing previous clones when possible.
    static <T> T
    deepClone(T object)
    Convenience utility function that creates a new Cloner, uses it to deep clone the object, and then returns the result.
    Returns a previously registered clone function for the specified type or null if there is no custom clone function for the type.
    boolean
    Returns true if the specified object has already been cloned by this cloner during this session.
    <T> T
    javaClone(T object)
    Performs a raw shallow Java clone using reflection.
    <T> void
    setClonedValue(T original, T clone)
    Forces an object to be added to the indexing cache such that attempts to clone the 'original' will always result in the 'clone' being returned.
    <T> void
    setCloneFunction(Class<T> type, CloneFunction<T> function)
    Sets a custom CloneFunction for implementations of the specified Java type.

    Methods inherited from class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Constructor Details

    • Cloner

      public Cloner()
      Creates a new cloner with only default clone functions and an empty object index.
  • Method Details

    • deepClone

      public static <T> T deepClone(T object)
      Convenience utility function that creates a new Cloner, uses it to deep clone the object, and then returns the result.
      Type Parameters:
      T - the type of object to be cloned
      Parameters:
      object - the object to be cloned (may be null)
      Returns:
      a new instance, or a cached value, or null
    • clone

      public <T> T clone(T object)
      Deeps clones the specified object, reusing previous clones when possible.

      Object cloning priority works as follows:

      • If the object has already been cloned then its clone is returned.
      • If there is a custom CloneFunction then it is called to clone the object.
      • If the object implements Cloneable then its clone() method is called, arrays are deep cloned with entries passing through clone().
      • If the object implements JmeCloneable then its cloneFields() method is called on the clone.
      • Else an IllegalArgumentException is thrown.
      Note: objects returned by this method may not have yet had their cloneField() method called.
      Type Parameters:
      T - the type of object to be cloned
      Parameters:
      object - the object to be cloned (may be null)
      Returns:
      a new instance, or a cached value, or null
    • clone

      public <T> T clone(T object, boolean useFunctions)
      Deeps clones the specified object, reusing previous clones when possible.

      Object cloning priority works as follows:

      • If the object has already been cloned then its clone is returned.
      • If useFunctions is true and there is a custom CloneFunction then it is called to clone the object.
      • If the object implements Cloneable then its clone() method is called, arrays are deep cloned with entries passing through clone().
      • If the object implements JmeCloneable then its cloneFields() method is called on the clone.
      • Else an IllegalArgumentException is thrown.

      The ability to selectively use clone functions is useful when being called from a clone function.

      Note: objects returned by this method may not have yet had their cloneField() method called.
      Type Parameters:
      T - the type of object to be cloned
      Parameters:
      object - the object to be cloned (may be null)
      useFunctions - true→use custom clone functions, false→don't use
      Returns:
      a new instance, or a cached value, or null
    • setCloneFunction

      public <T> void setCloneFunction(Class<T> type, CloneFunction<T> function)
      Sets a custom CloneFunction for implementations of the specified Java type. Some inheritance checks are made but no disambiguation is performed.

      Note: in the general case, it is better to register against specific classes and not super-classes or super-interfaces unless you know specifically that they are cloneable.

      By default ListCloneFunction is registered for ArrayList, LinkedList, CopyOnWriteArrayList, Vector, Stack, and JME's SafeArrayList.

      Type Parameters:
      T - the type of object to be cloned
      Parameters:
      type - the type of object to be cloned
      function - the function to set, or null to cancel any previous setting
    • getCloneFunction

      public <T> CloneFunction<T> getCloneFunction(Class<T> type)
      Returns a previously registered clone function for the specified type or null if there is no custom clone function for the type.
      Type Parameters:
      T - the type of object to be cloned
      Parameters:
      type - the type of object to be cloned
      Returns:
      the registered function, or null if none
    • setClonedValue

      public <T> void setClonedValue(T original, T clone)
      Forces an object to be added to the indexing cache such that attempts to clone the 'original' will always result in the 'clone' being returned. This can be used to stub out specific values from being cloned or to force global shared instances to be used even if the object is cloneable normally.
      Type Parameters:
      T - the type of object to be detected and returned
      Parameters:
      original - the instance to be detected (alias created)
      clone - the instance to be returned (alias created)
    • isCloned

      public boolean isCloned(Object o)
      Returns true if the specified object has already been cloned by this cloner during this session. Cloned objects are cached for later use, and it's sometimes convenient to know if some objects have already been cloned.
      Parameters:
      o - the object to be tested
      Returns:
      true if the object has been cloned, otherwise false
    • clearIndex

      public void clearIndex()
      Clears the object index allowing the cloner to be reused for a brand-new cloning operation.
    • javaClone

      public <T> T javaClone(T object) throws CloneNotSupportedException
      Performs a raw shallow Java clone using reflection. This call does NOT check against the clone index and so will return new objects every time it is called. That's because these are shallow clones and have not (and may not ever, depending on the caller) get resolved.

      This method is provided as a convenient way for CloneFunctions to call clone() and objects without necessarily knowing their real type.

      Type Parameters:
      T - the type of object to be cloned
      Parameters:
      object - the object to be cloned (may be null)
      Returns:
      a new instance or null
      Throws:
      CloneNotSupportedException - if the object has no public clone method
    • arrayClone

      protected <T> T arrayClone(T object)
      Clones a primitive array by coping it and clones an object array by coping it and then running each of its values through Cloner.clone().
      Type Parameters:
      T - the type of array to be cloned
      Parameters:
      object - the array to be cloned
      Returns:
      a new array