|
@@ -0,0 +1,368 @@
|
|
|
+/*
|
|
|
+ * Copyright (c) 2016 jMonkeyEngine
|
|
|
+ * All rights reserved.
|
|
|
+ *
|
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
|
+ * modification, are permitted provided that the following conditions are
|
|
|
+ * met:
|
|
|
+ *
|
|
|
+ * * Redistributions of source code must retain the above copyright
|
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
|
+ *
|
|
|
+ * * Redistributions in binary form must reproduce the above copyright
|
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
|
+ *
|
|
|
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
|
|
+ * may be used to endorse or promote products derived from this software
|
|
|
+ * without specific prior written permission.
|
|
|
+ *
|
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
|
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
|
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
|
|
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
|
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
|
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
|
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
|
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
|
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
|
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
+ */
|
|
|
+
|
|
|
+package jme3test.app;
|
|
|
+
|
|
|
+import java.util.*;
|
|
|
+
|
|
|
+import com.jme3.util.clone.*;
|
|
|
+
|
|
|
+/**
|
|
|
+ *
|
|
|
+ *
|
|
|
+ * @author Paul Speed
|
|
|
+ */
|
|
|
+public class TestCloner {
|
|
|
+
|
|
|
+ public static void main( String... args ) {
|
|
|
+
|
|
|
+ System.out.println("Clone test:");
|
|
|
+
|
|
|
+ Cloner cloner = new Cloner();
|
|
|
+
|
|
|
+ RegularObject ro = new RegularObject(42);
|
|
|
+ System.out.println("Regular Object:" + ro);
|
|
|
+ RegularObject roCloneLegacy = ro.clone();
|
|
|
+ System.out.println("Regular Object Clone:" + roCloneLegacy);
|
|
|
+ RegularObject roClone = cloner.clone(ro);
|
|
|
+ System.out.println("cloner: Regular Object Clone:" + roClone);
|
|
|
+
|
|
|
+ System.out.println("------------------------------------");
|
|
|
+ System.out.println();
|
|
|
+
|
|
|
+ cloner = new Cloner();
|
|
|
+ RegularSubclass rsc = new RegularSubclass(69, "test");
|
|
|
+ System.out.println("Regular subclass:" + rsc);
|
|
|
+ RegularSubclass rscCloneLegacy = (RegularSubclass)rsc.clone();
|
|
|
+ System.out.println("Regular subclass Clone:" + rscCloneLegacy);
|
|
|
+ RegularSubclass rscClone = cloner.clone(rsc);
|
|
|
+ System.out.println("cloner: Regular subclass Clone:" + rscClone);
|
|
|
+
|
|
|
+ System.out.println("------------------------------------");
|
|
|
+ System.out.println();
|
|
|
+
|
|
|
+ cloner = new Cloner();
|
|
|
+ Parent parent = new Parent("Foo", 34);
|
|
|
+ System.out.println("Parent:" + parent);
|
|
|
+ Parent parentCloneLegacy = parent.clone();
|
|
|
+ System.out.println("Parent Clone:" + parentCloneLegacy);
|
|
|
+ Parent parentClone = cloner.clone(parent);
|
|
|
+ System.out.println("cloner: Parent Clone:" + parentClone);
|
|
|
+
|
|
|
+ System.out.println("------------------------------------");
|
|
|
+ System.out.println();
|
|
|
+
|
|
|
+ cloner = new Cloner();
|
|
|
+ GraphNode root = new GraphNode("root");
|
|
|
+ GraphNode child1 = root.addLink("child1");
|
|
|
+ GraphNode child2 = root.addLink("child2");
|
|
|
+ GraphNode shared = child1.addLink("shared");
|
|
|
+ child2.addLink(shared);
|
|
|
+
|
|
|
+ // Add a circular reference to get fancy
|
|
|
+ shared.addLink(root);
|
|
|
+
|
|
|
+ System.out.println("Simple graph:");
|
|
|
+ root.dump(" ");
|
|
|
+
|
|
|
+ GraphNode rootClone = cloner.clone(root);
|
|
|
+ System.out.println("clone:");
|
|
|
+ rootClone.dump(" ");
|
|
|
+
|
|
|
+ System.out.println("original:");
|
|
|
+ root.dump(" ");
|
|
|
+
|
|
|
+ GraphNode reclone = Cloner.deepClone(root);
|
|
|
+ System.out.println("reclone:");
|
|
|
+ reclone.dump(" ");
|
|
|
+
|
|
|
+ System.out.println("------------------------------------");
|
|
|
+ System.out.println();
|
|
|
+ cloner = new Cloner();
|
|
|
+
|
|
|
+ ArrayHolder arrays = new ArrayHolder(5, 3, 7, 3, 7, 2, 1, 4);
|
|
|
+ System.out.println("Array holder:" + arrays);
|
|
|
+ ArrayHolder arraysClone = cloner.clone(arrays);
|
|
|
+ System.out.println("Array holder clone:" + arraysClone);
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ public static class RegularObject implements Cloneable {
|
|
|
+ protected int i;
|
|
|
+
|
|
|
+ public RegularObject( int i ) {
|
|
|
+ this.i = i;
|
|
|
+ }
|
|
|
+
|
|
|
+ public RegularObject clone() {
|
|
|
+ try {
|
|
|
+ return (RegularObject)super.clone();
|
|
|
+ } catch( CloneNotSupportedException e ) {
|
|
|
+ throw new RuntimeException(e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public String toString() {
|
|
|
+ return getClass().getSimpleName() + "@" + System.identityHashCode(this)
|
|
|
+ + "[i=" + i + "]";
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public static class RegularSubclass extends RegularObject {
|
|
|
+ protected String name;
|
|
|
+
|
|
|
+ public RegularSubclass( int i, String name ) {
|
|
|
+ super(i);
|
|
|
+ this.name = name;
|
|
|
+ }
|
|
|
+
|
|
|
+ public String toString() {
|
|
|
+ return getClass().getSimpleName() + "@" + System.identityHashCode(this)
|
|
|
+ + "[i=" + i + ", name=" + name + "]";
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public static class Parent implements Cloneable, JmeCloneable {
|
|
|
+
|
|
|
+ private RegularObject ro;
|
|
|
+ private RegularSubclass rsc;
|
|
|
+
|
|
|
+ public Parent( String name, int age ) {
|
|
|
+ this.ro = new RegularObject(age);
|
|
|
+ this.rsc = new RegularSubclass(age, name);
|
|
|
+ }
|
|
|
+
|
|
|
+ public Parent clone() {
|
|
|
+ try {
|
|
|
+ return (Parent)super.clone();
|
|
|
+ } catch( CloneNotSupportedException e ) {
|
|
|
+ throw new RuntimeException(e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public void cloneFields( Cloner cloner, Object original ) {
|
|
|
+ this.ro = cloner.clone(ro);
|
|
|
+ this.rsc = cloner.clone(rsc);
|
|
|
+ }
|
|
|
+
|
|
|
+ public String toString() {
|
|
|
+ return getClass().getSimpleName() + "@" + System.identityHashCode(this)
|
|
|
+ + "[ro=" + ro + ", rsc=" + rsc + "]";
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public static class GraphNode implements Cloneable, JmeCloneable {
|
|
|
+
|
|
|
+ private String name;
|
|
|
+ private List<GraphNode> links = new ArrayList<>();
|
|
|
+
|
|
|
+ public GraphNode( String name ) {
|
|
|
+ this.name = name;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void dump( String indent ) {
|
|
|
+ dump(indent, new HashSet<GraphNode>());
|
|
|
+ }
|
|
|
+
|
|
|
+ private void dump( String indent, Set<GraphNode> visited ) {
|
|
|
+ if( visited.contains(this) ) {
|
|
|
+ // already been here
|
|
|
+ System.out.println(indent + this + " ** circular.");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ System.out.println(indent + this);
|
|
|
+ visited.add(this);
|
|
|
+ for( GraphNode n : links ) {
|
|
|
+ n.dump(indent + " ", visited);
|
|
|
+ }
|
|
|
+ visited.remove(this);
|
|
|
+ }
|
|
|
+
|
|
|
+ public GraphNode addLink( String name ) {
|
|
|
+ GraphNode node = new GraphNode(name);
|
|
|
+ links.add(node);
|
|
|
+ return node;
|
|
|
+ }
|
|
|
+
|
|
|
+ public GraphNode addLink( GraphNode node ) {
|
|
|
+ links.add(node);
|
|
|
+ return node;
|
|
|
+ }
|
|
|
+
|
|
|
+ public List<GraphNode> getLinks() {
|
|
|
+ return links;
|
|
|
+ }
|
|
|
+
|
|
|
+ public GraphNode clone() {
|
|
|
+ try {
|
|
|
+ return (GraphNode)super.clone();
|
|
|
+ } catch( CloneNotSupportedException e ) {
|
|
|
+ throw new RuntimeException(e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public void cloneFields( Cloner cloner, Object original ) {
|
|
|
+ this.links = cloner.clone(links);
|
|
|
+ /*
|
|
|
+ // manually clone the list for a sec
|
|
|
+ List<GraphNode> cloneList = (List<GraphNode>)((ArrayList<GraphNode>)links).clone(); //new ArrayList<GraphNode>();
|
|
|
+ for( int i = 0; i < links.size(); i++ ) {
|
|
|
+ cloneList.set(i, cloner.clone(links.get(i)));
|
|
|
+ }
|
|
|
+ links = cloneList;*/
|
|
|
+ }
|
|
|
+
|
|
|
+ public String toString() {
|
|
|
+ return getClass().getSimpleName() + "@" + System.identityHashCode(this)
|
|
|
+ + "[name=" + name + "]";
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public static class ArrayHolder implements JmeCloneable {
|
|
|
+
|
|
|
+ private int[] intArray;
|
|
|
+ private int[][] intArray2D;
|
|
|
+ private Object[] objects;
|
|
|
+ private RegularObject[] regularObjects;
|
|
|
+ private String[] strings;
|
|
|
+
|
|
|
+ public ArrayHolder( int... values ) {
|
|
|
+ this.intArray = values;
|
|
|
+ this.intArray2D = new int[values.length][2];
|
|
|
+ for( int i = 0; i < values.length; i++ ) {
|
|
|
+ intArray2D[i][0] = values[i] + 1;
|
|
|
+ intArray2D[i][1] = values[i] * 2;
|
|
|
+ }
|
|
|
+ this.objects = new Object[values.length];
|
|
|
+ this.regularObjects = new RegularObject[values.length];
|
|
|
+ this.strings = new String[values.length];
|
|
|
+ for( int i = 0; i < values.length; i++ ) {
|
|
|
+ objects[i] = values[i];
|
|
|
+ regularObjects[i] = new RegularObject(values[i]);
|
|
|
+ strings[i] = String.valueOf(values[i]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public ArrayHolder clone() {
|
|
|
+ try {
|
|
|
+ return (ArrayHolder)super.clone();
|
|
|
+ } catch( CloneNotSupportedException e ) {
|
|
|
+ throw new RuntimeException(e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public void cloneFields( Cloner cloner, Object original ) {
|
|
|
+ intArray = cloner.clone(intArray);
|
|
|
+ intArray2D = cloner.clone(intArray2D);
|
|
|
+
|
|
|
+ // Boxed types are not cloneable so this will fail
|
|
|
+ //objects = cloner.clone(objects);
|
|
|
+
|
|
|
+ regularObjects = cloner.clone(regularObjects);
|
|
|
+
|
|
|
+ // Strings are also not cloneable
|
|
|
+ //strings = cloner.clone(strings);
|
|
|
+ }
|
|
|
+
|
|
|
+ public String toString() {
|
|
|
+ StringBuilder sb = new StringBuilder();
|
|
|
+ sb.append("intArray=" + intArray);
|
|
|
+ for( int i = 0; i < intArray.length; i++ ) {
|
|
|
+ if( i == 0 ) {
|
|
|
+ sb.append("[");
|
|
|
+ } else {
|
|
|
+ sb.append(", ");
|
|
|
+ }
|
|
|
+ sb.append(intArray[i]);
|
|
|
+ }
|
|
|
+ sb.append("], ");
|
|
|
+
|
|
|
+ sb.append("intArray2D=" + intArray2D);
|
|
|
+ for( int i = 0; i < intArray2D.length; i++ ) {
|
|
|
+ if( i == 0 ) {
|
|
|
+ sb.append("[");
|
|
|
+ } else {
|
|
|
+ sb.append(", ");
|
|
|
+ }
|
|
|
+ sb.append("intArray2D[" + i + "]=" + intArray2D[i]);
|
|
|
+ for( int j = 0; j < 2; j++ ) {
|
|
|
+ if( j == 0 ) {
|
|
|
+ sb.append("[");
|
|
|
+ } else {
|
|
|
+ sb.append(", ");
|
|
|
+ }
|
|
|
+ sb.append(intArray2D[i][j]);
|
|
|
+ }
|
|
|
+ sb.append("], ");
|
|
|
+ }
|
|
|
+ sb.append("], ");
|
|
|
+
|
|
|
+ sb.append("objectArray=" + objects);
|
|
|
+ for( int i = 0; i < objects.length; i++ ) {
|
|
|
+ if( i == 0 ) {
|
|
|
+ sb.append("[");
|
|
|
+ } else {
|
|
|
+ sb.append(", ");
|
|
|
+ }
|
|
|
+ sb.append(objects[i]);
|
|
|
+ }
|
|
|
+ sb.append("], ");
|
|
|
+
|
|
|
+ sb.append("objectArray=" + regularObjects);
|
|
|
+ for( int i = 0; i < regularObjects.length; i++ ) {
|
|
|
+ if( i == 0 ) {
|
|
|
+ sb.append("[");
|
|
|
+ } else {
|
|
|
+ sb.append(", ");
|
|
|
+ }
|
|
|
+ sb.append(regularObjects[i]);
|
|
|
+ }
|
|
|
+ sb.append("], ");
|
|
|
+
|
|
|
+ sb.append("stringArray=" + strings);
|
|
|
+ for( int i = 0; i < strings.length; i++ ) {
|
|
|
+ if( i == 0 ) {
|
|
|
+ sb.append("[");
|
|
|
+ } else {
|
|
|
+ sb.append(", ");
|
|
|
+ }
|
|
|
+ sb.append(strings[i]);
|
|
|
+ }
|
|
|
+ sb.append("]");
|
|
|
+
|
|
|
+ return getClass().getSimpleName() + "@" + System.identityHashCode(this)
|
|
|
+ + "[" + sb + "]";
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|