From 10947e8b5096f6d7e2bf0e327faa43b275adeb34 Mon Sep 17 00:00:00 2001 From: Paul Speed Date: Thu, 10 Mar 2016 04:25:43 -0500 Subject: [PATCH] Modified the JmeCloneable's clone() method to be jmeClone() so that implementing objects will still be able to keep a regular public clone() method that may do their own selective deep cloning. This allows explicit demarcation between the normal 'user' facing clone() and the two step cloning process used by Cloner. Specifically, this will let Spatial continue to have a clone() method that operates as it does today... with its new guts essentially calling a properly configured Cloner. --- .../main/java/com/jme3/util/clone/Cloner.java | 16 ++++++++++------ .../java/com/jme3/util/clone/JmeCloneable.java | 16 ++++++++++++++-- .../src/main/java/jme3test/app/TestCloner.java | 10 ++++++++-- 3 files changed, 32 insertions(+), 10 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/util/clone/Cloner.java b/jme3-core/src/main/java/com/jme3/util/clone/Cloner.java index d5ffa10de..cc046b28a 100644 --- a/jme3-core/src/main/java/com/jme3/util/clone/Cloner.java +++ b/jme3-core/src/main/java/com/jme3/util/clone/Cloner.java @@ -221,7 +221,17 @@ public class Cloner { clone = arrayClone(object); // Array clone already indexes the clone + } else if( object instanceof JmeCloneable ) { + // Use the two-step cloning semantics + clone = ((JmeCloneable)object).jmeClone(); + + // Store the object in the identity map so that any circular references + // are resolvable + index.put(object, clone); + + ((JmeCloneable)clone).cloneFields(this, object); } else if( object instanceof Cloneable ) { + // Perform a regular Java shallow clone try { clone = javaClone(object); @@ -236,12 +246,6 @@ public class Cloner { throw new IllegalArgumentException("Object is not cloneable, type:" + type); } - // Finally, check to see if the object implements special field cloning - // behavior. - if( clone instanceof JmeCloneable ) { - ((JmeCloneable)clone).cloneFields(this, object); - } - return type.cast(clone); } diff --git a/jme3-core/src/main/java/com/jme3/util/clone/JmeCloneable.java b/jme3-core/src/main/java/com/jme3/util/clone/JmeCloneable.java index 28049e0f1..6b278b222 100644 --- a/jme3-core/src/main/java/com/jme3/util/clone/JmeCloneable.java +++ b/jme3-core/src/main/java/com/jme3/util/clone/JmeCloneable.java @@ -61,9 +61,21 @@ package com.jme3.util.clone; public interface JmeCloneable extends Cloneable { /** - * Performs a shallow clone of the object. + * Performs a regular shallow clone of the object. Some fields + * may also be cloned but generally only if they will never be + * shared with other objects. (For example, local Vector3fs and so on.) + * + *

This method is separate from the regular clone() method + * so that objects might still maintain their own regular java clone() + * semantics (perhaps even using Cloner for those methods). However, + * because Java's clone() has specific features in the sense of Object's + * clone() implementation, it's usually best to have some path for + * subclasses to bypass the public clone() method that might be cloning + * fields and instead get at the superclass protected clone() methods. + * For example, through super.jmeClone() or another protected clone + * method that some base class eventually calls super.clone() in.

*/ - public Object clone(); + public Object jmeClone(); /** * Implemented to perform deep cloning for this object, resolving diff --git a/jme3-examples/src/main/java/jme3test/app/TestCloner.java b/jme3-examples/src/main/java/jme3test/app/TestCloner.java index b28647a23..4ae105603 100644 --- a/jme3-examples/src/main/java/jme3test/app/TestCloner.java +++ b/jme3-examples/src/main/java/jme3test/app/TestCloner.java @@ -170,6 +170,12 @@ public class TestCloner { throw new RuntimeException(e); } } + + public Parent jmeClone() { + // Ok to delegate to clone() in this case because no deep + // cloning is done there. + return clone(); + } public void cloneFields( Cloner cloner, Object original ) { this.ro = cloner.clone(ro); @@ -224,7 +230,7 @@ public class TestCloner { return links; } - public GraphNode clone() { + public GraphNode jmeClone() { try { return (GraphNode)super.clone(); } catch( CloneNotSupportedException e ) { @@ -267,7 +273,7 @@ public class TestCloner { } } - public ArrayHolder clone() { + public ArrayHolder jmeClone() { try { return (ArrayHolder)super.clone(); } catch( CloneNotSupportedException e ) {