public class Cloner
extends java.lang.Object
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:
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 and Description |
---|
Cloner()
Creates a new cloner with only default clone functions and an empty
object index.
|
Modifier and Type | Method and 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 |
clearIndex()
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.
|
<T> CloneFunction<T> |
getCloneFunction(java.lang.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.
|
boolean |
isCloned(java.lang.Object o)
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(java.lang.Class<T> type,
CloneFunction<T> function)
Sets a custom CloneFunction for implementations of the specified Java type.
|
public Cloner()
public static <T> T deepClone(T object)
T
- the type of object to be clonedobject
- the object to be cloned (may be null)public <T> T clone(T object)
Object cloning priority works as follows:
T
- the type of object to be clonedobject
- the object to be cloned (may be null)public <T> T clone(T object, boolean useFunctions)
Object cloning priority works as follows:
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.T
- the type of object to be clonedobject
- the object to be cloned (may be null)useFunctions
- true→use custom clone functions,
false→don't usepublic <T> void setCloneFunction(java.lang.Class<T> type, CloneFunction<T> function)
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.
T
- the type of object to be clonedtype
- the type of object to be clonedfunction
- the function to set, or null to cancel any previous
settingpublic <T> CloneFunction<T> getCloneFunction(java.lang.Class<T> type)
T
- the type of object to be clonedtype
- the type of object to be clonedpublic <T> void setClonedValue(T original, T clone)
T
- the type of object to be detected and returnedoriginal
- the instance to be detected (alias created)clone
- the instance to be returned (alias created)public boolean isCloned(java.lang.Object o)
o
- the object to be testedpublic void clearIndex()
public <T> T javaClone(T object) throws java.lang.CloneNotSupportedException
This method is provided as a convenient way for CloneFunctions to call clone() and objects without necessarily knowing their real type.
T
- the type of object to be clonedobject
- the object to be cloned (may be null)java.lang.CloneNotSupportedException
- if the object has no public clone methodprotected <T> T arrayClone(T object)
T
- the type of array to be clonedobject
- the array to be cloned