From 36abfc965dcc2f345e175ffe7911de9e9fc202c9 Mon Sep 17 00:00:00 2001 From: jia Date: Fri, 23 Jul 2021 15:01:01 +0800 Subject: [PATCH 1/9] feat:FastClonerListOf12 and FastClonerSetOf12 --- src/main/java/com/rits/cloning/Cloner.java | 5 +++++ .../com/rits/cloning/FastClonerListOf12.java | 20 +++++++++++++++++++ .../com/rits/cloning/FastClonerSetOf12.java | 18 +++++++++++++++++ .../com/rits/tests/cloning/TestCloner.java | 8 ++++++++ 4 files changed, 51 insertions(+) create mode 100644 src/main/java/com/rits/cloning/FastClonerListOf12.java create mode 100644 src/main/java/com/rits/cloning/FastClonerSetOf12.java diff --git a/src/main/java/com/rits/cloning/Cloner.java b/src/main/java/com/rits/cloning/Cloner.java index 53b6d9f..1696b02 100644 --- a/src/main/java/com/rits/cloning/Cloner.java +++ b/src/main/java/com/rits/cloning/Cloner.java @@ -5,6 +5,7 @@ import java.lang.annotation.Annotation; import java.lang.reflect.Array; import java.lang.reflect.Field; + import java.lang.reflect.Modifier; import java.math.BigDecimal; import java.math.BigInteger; @@ -113,6 +114,10 @@ protected void registerFastCloners() { registerInaccessibleClassToBeFastCloned("java.util.ArrayList$SubList", subListCloner); registerInaccessibleClassToBeFastCloned("java.util.SubList", subListCloner); registerInaccessibleClassToBeFastCloned("java.util.RandomAccessSubList", subListCloner); + FastClonerListOf12 listOf12 = new FastClonerListOf12(); + registerInaccessibleClassToBeFastCloned("java.util.ImmutableCollections$List12",listOf12); + FastClonerSetOf12 setOf12 = new FastClonerSetOf12(); + registerInaccessibleClassToBeFastCloned("java.util.ImmutableCollections$Set12",setOf12); } protected void registerInaccessibleClassToBeFastCloned(String className, IFastCloner fastCloner) { diff --git a/src/main/java/com/rits/cloning/FastClonerListOf12.java b/src/main/java/com/rits/cloning/FastClonerListOf12.java new file mode 100644 index 0000000..bd56a8f --- /dev/null +++ b/src/main/java/com/rits/cloning/FastClonerListOf12.java @@ -0,0 +1,20 @@ +package com.rits.cloning; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class FastClonerListOf12 implements IFastCloner { + @SuppressWarnings({"unchecked", "rawtypes"}) + public Object clone(final Object t, final IDeepCloner cloner, final Map clones) { + List al = (List) t; + if (al.size()==1){ + return List.of(al.get(0)); + }else if (al.size()==2){ + return List.of(al.get(0),al.get(1)); + }else { + return new ArrayList<>(); + } + } + +} diff --git a/src/main/java/com/rits/cloning/FastClonerSetOf12.java b/src/main/java/com/rits/cloning/FastClonerSetOf12.java new file mode 100644 index 0000000..2e024df --- /dev/null +++ b/src/main/java/com/rits/cloning/FastClonerSetOf12.java @@ -0,0 +1,18 @@ +package com.rits.cloning; + +import java.util.*; + +public class FastClonerSetOf12 implements IFastCloner{ + @SuppressWarnings({"unchecked", "rawtypes"}) + public Object clone(final Object t, final IDeepCloner cloner, final Map clones) { + Set set=(Set) t; + Object[] a=set.toArray(); + if (set.size()==1){ + return Set.of(a[0]); + }else if (set.size()==2){ + return Set.of(a[0],a[1]); + }else { + return new HashSet<>(); + } + } +} diff --git a/src/test/java/com/rits/tests/cloning/TestCloner.java b/src/test/java/com/rits/tests/cloning/TestCloner.java index cf3f97f..8dd240a 100644 --- a/src/test/java/com/rits/tests/cloning/TestCloner.java +++ b/src/test/java/com/rits/tests/cloning/TestCloner.java @@ -39,6 +39,14 @@ public class TestCloner extends TestCase { static private class MyAX { } + public void testCloneListOf12(){ + Assert.assertEquals(1, cloner.deepClone(List.of(1)).size()); + } + + public void testCloneSetOf12(){ + Assert.assertEquals(1, cloner.deepClone(Set.of(1)).size()); + } + public void testCalendarTimezone() { TimeZone timeZone = TimeZone.getTimeZone("America/Los_Angeles"); Calendar c = Calendar.getInstance(timeZone); From 03b4242f45722c37d06af3324168889aaf36cfd3 Mon Sep 17 00:00:00 2001 From: "kostas.kougios@gmail.com" Date: Fri, 23 Jul 2021 11:59:34 +0100 Subject: [PATCH 2/9] update objenesis to 3.2 --- pom.xml | 2 +- src/test/java/com/rits/tests/cloning/TestCloner.java | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e3f158d..218f320 100644 --- a/pom.xml +++ b/pom.xml @@ -137,7 +137,7 @@ org.objenesis objenesis - 3.0.1 + 3.2 diff --git a/src/test/java/com/rits/tests/cloning/TestCloner.java b/src/test/java/com/rits/tests/cloning/TestCloner.java index cf3f97f..10d5419 100644 --- a/src/test/java/com/rits/tests/cloning/TestCloner.java +++ b/src/test/java/com/rits/tests/cloning/TestCloner.java @@ -10,8 +10,10 @@ import java.lang.annotation.Retention; import java.lang.annotation.Target; +import java.time.ZonedDateTime; import java.util.*; import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.function.Function; import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.RetentionPolicy.RUNTIME; @@ -915,5 +917,11 @@ class StaticTransient extends ArrayList { cloner.deepClone(new StaticTransient()); } + + public void ignoreTestLambda() { + // this fails with "Caused by: java.lang.ClassNotFoundException: com.rits.tests.cloning.TestCloner$$Lambda$54.0x0000000800c24210" + Function f = ZonedDateTime::getNano; + cloner.deepClone(f); + } } From b0ff9568d5749451c444c4422721af51bd513db2 Mon Sep 17 00:00:00 2001 From: jia Date: Sat, 24 Jul 2021 09:07:18 +0800 Subject: [PATCH 3/9] feat:FastClonerListOf12 and FastClonerSetOf12 --- .../com/rits/cloning/FastClonerListOf12.java | 12 +++++++----- .../com/rits/cloning/FastClonerSetOf12.java | 18 ++++++++++-------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/rits/cloning/FastClonerListOf12.java b/src/main/java/com/rits/cloning/FastClonerListOf12.java index bd56a8f..2990b04 100644 --- a/src/main/java/com/rits/cloning/FastClonerListOf12.java +++ b/src/main/java/com/rits/cloning/FastClonerListOf12.java @@ -8,11 +8,13 @@ public class FastClonerListOf12 implements IFastCloner { @SuppressWarnings({"unchecked", "rawtypes"}) public Object clone(final Object t, final IDeepCloner cloner, final Map clones) { List al = (List) t; - if (al.size()==1){ - return List.of(al.get(0)); - }else if (al.size()==2){ - return List.of(al.get(0),al.get(1)); - }else { + if (al.size() == 1) { + return List.of(cloner.deepClone(al.get(0), clones)); + } else if (al.size() == 2) { + Object o1 = cloner.deepClone(al.get(0), clones); + Object o2 = cloner.deepClone(al.get(1), clones); + return List.of(o1, o2); + } else { return new ArrayList<>(); } } diff --git a/src/main/java/com/rits/cloning/FastClonerSetOf12.java b/src/main/java/com/rits/cloning/FastClonerSetOf12.java index 2e024df..d5bd0b9 100644 --- a/src/main/java/com/rits/cloning/FastClonerSetOf12.java +++ b/src/main/java/com/rits/cloning/FastClonerSetOf12.java @@ -2,16 +2,18 @@ import java.util.*; -public class FastClonerSetOf12 implements IFastCloner{ +public class FastClonerSetOf12 implements IFastCloner { @SuppressWarnings({"unchecked", "rawtypes"}) public Object clone(final Object t, final IDeepCloner cloner, final Map clones) { - Set set=(Set) t; - Object[] a=set.toArray(); - if (set.size()==1){ - return Set.of(a[0]); - }else if (set.size()==2){ - return Set.of(a[0],a[1]); - }else { + Set set = (Set) t; + Object[] a = set.toArray(); + if (set.size() == 1) { + return Set.of(cloner.deepClone(a[0], clones)); + } else if (set.size() == 2) { + Object o1 = cloner.deepClone(a[0], clones); + Object o2 = cloner.deepClone(a[1], clones); + return Set.of(o1, o2); + } else { return new HashSet<>(); } } From 6360525202bffc60edf7b09630b04641768b54ab Mon Sep 17 00:00:00 2001 From: "kostas.kougios@gmail.com" Date: Fri, 30 Jul 2021 21:30:48 +0100 Subject: [PATCH 4/9] ClassWithEnum tests --- src/test/java/com/rits/tests/cloning/TestCloner.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/test/java/com/rits/tests/cloning/TestCloner.java b/src/test/java/com/rits/tests/cloning/TestCloner.java index 10d5419..2d4ec35 100644 --- a/src/test/java/com/rits/tests/cloning/TestCloner.java +++ b/src/test/java/com/rits/tests/cloning/TestCloner.java @@ -13,6 +13,7 @@ import java.time.ZonedDateTime; import java.util.*; import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.TimeUnit; import java.util.function.Function; import static java.lang.annotation.ElementType.TYPE; @@ -923,5 +924,16 @@ public void ignoreTestLambda() { Function f = ZonedDateTime::getNano; cloner.deepClone(f); } + + private static class ClassWithEnum { + TimeUnit timeUnit; + } + + public void testClassWithEnum() { + ClassWithEnum a = new ClassWithEnum(); + a.timeUnit = TimeUnit.SECONDS; + ClassWithEnum b = cloner.deepClone(a); + assertSame(TimeUnit.SECONDS, b.timeUnit); + } } From d7ef524966c6b48af897692a9d98a200be41320e Mon Sep 17 00:00:00 2001 From: "kostas.kougios@gmail.com" Date: Sat, 31 Jul 2021 18:10:48 +0100 Subject: [PATCH 5/9] fix typo --- src/test/java/com/rits/tests/cloning/TestCloner.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/rits/tests/cloning/TestCloner.java b/src/test/java/com/rits/tests/cloning/TestCloner.java index 2d4ec35..1880279 100644 --- a/src/test/java/com/rits/tests/cloning/TestCloner.java +++ b/src/test/java/com/rits/tests/cloning/TestCloner.java @@ -878,7 +878,7 @@ public void testLinkedHashSetEquals() { /** * Test if insertion order of LinkedhashSet is the same */ - public void testLinkedHashSetInserationOrder() { + public void testLinkedHashSetIterationOrder() { LinkedHashSet originalSet = new LinkedHashSet<>(); for (int i = 1000; i >= 1; i--) { originalSet.add(i); From 69ee3e638f9ddeae51b3f2e9019636cfb4c1f520 Mon Sep 17 00:00:00 2001 From: jia Date: Tue, 3 Aug 2021 14:30:16 +0800 Subject: [PATCH 6/9] add FastClonerListOf12 test case --- .../com/rits/tests/cloning/TestCloner.java | 1864 +++++++++-------- 1 file changed, 937 insertions(+), 927 deletions(-) diff --git a/src/test/java/com/rits/tests/cloning/TestCloner.java b/src/test/java/com/rits/tests/cloning/TestCloner.java index 8dd240a..04b2f8f 100644 --- a/src/test/java/com/rits/tests/cloning/TestCloner.java +++ b/src/test/java/com/rits/tests/cloning/TestCloner.java @@ -1,927 +1,937 @@ -package com.rits.tests.cloning; - -import com.rits.cloning.Cloner; -import com.rits.cloning.FastClonerHashMap; -import com.rits.cloning.Immutable; -import com.rits.tests.cloning.TestCloner.SynthOuter.Inner; -import com.rits.tests.cloning.domain.*; -import junit.framework.TestCase; -import org.junit.Assert; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; -import java.util.*; -import java.util.concurrent.ConcurrentLinkedQueue; - -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.RUNTIME; -import static org.junit.Assert.assertNotEquals; - -/** - * @author kostantinos.kougios - *

- * 18 Sep 2008 - */ -public class TestCloner extends TestCase { - private final Cloner cloner = new Cloner(); - - { - cloner.setDumpClonedClasses(false); - } - - @Target(TYPE) - @Retention(RUNTIME) - private @interface MyImmutable { - - } - - @MyImmutable - static private class MyAX { - } - - public void testCloneListOf12(){ - Assert.assertEquals(1, cloner.deepClone(List.of(1)).size()); - } - - public void testCloneSetOf12(){ - Assert.assertEquals(1, cloner.deepClone(Set.of(1)).size()); - } - - public void testCalendarTimezone() { - TimeZone timeZone = TimeZone.getTimeZone("America/Los_Angeles"); - Calendar c = Calendar.getInstance(timeZone); - Calendar cloned = cloner.deepClone(c); - assertEquals(timeZone, cloned.getTimeZone()); - } - - public void testCloneEnumInMapIssue20() { - Map m = new HashMap<>(); - m.put(1, TestEnum.A); - m.put(2, TestEnum.B); - m.put(3, TestEnum.C); - Map clone = cloner.deepClone(m); - - assertSame(clone.get(1), TestEnum.A); - assertSame(clone.get(2), TestEnum.B); - assertSame(clone.get(3), TestEnum.C); - } - - public void testCustomAnnotation() { - final Cloner cloner = new Cloner() { - @Override - protected Class getImmutableAnnotation() { - return MyImmutable.class; - } - }; - final MyAX o = new MyAX(); - final MyAX c = cloner.deepClone(o); - assertSame(o, c); - } - - public void testConsiderImmutable() { - final Cloner cloner = new Cloner() { - @Override - protected boolean considerImmutable(final Class clz) { - return clz == Object.class; - } - }; - final Object o = new Object(); - final Object c = cloner.deepClone(o); - assertSame(o, c); - } - - class X { - private X(int x) { - x = 5; - } - } - - @Immutable(subClass = true) - static public class ATestImmutable { - } - - static public class ATestImmutableSubclass extends ATestImmutable { - - } - - @Immutable - static public class BTestImmutable { - } - - static public class BTestImmutableSubclass extends BTestImmutable { - } - - public void testIssue7() { - final HashMap source = new HashMap<>(); - source.put("string", "string"); - source.put("array", new Integer[]{1, 2, 3}); - final HashMap sc = cloner.shallowClone(source); - assertEquals("string", sc.get("string")); - } - - public void testIgnoreInstanceOf() { - final Cloner cloner = new Cloner(); - cloner.dontCloneInstanceOf(A.class); - - final A a = new A() { - }; - assertNotSame(a.getClass(), A.class); - assertSame(a, cloner.deepClone(a)); - } - - public void testImmutableSubclassNotEnabled() { - final BTestImmutableSubclass a = new BTestImmutableSubclass(); - final BTestImmutableSubclass ca = cloner.deepClone(a); - assertNotSame(a, ca); - } - - public void testImmutableSubclass() { - final ATestImmutableSubclass a = new ATestImmutableSubclass(); - assertSame(a, cloner.deepClone(a)); - assertSame(a, cloner.deepClone(a)); - } - - public void testImmutable() { - final ATestImmutable a = new ATestImmutable(); - assertSame(a, cloner.deepClone(a)); - assertSame(a, cloner.deepClone(a)); - } - - /** - * tests if it happens that in the deep-graph of the cloned objects, - * if a reference to the same object exists twice, the cloned object - * will have only 1 clone and references to this clone. - */ - public void testCloningOfSameObject() { - final Object o1 = new Object(); - final Object o2 = new Object(); - class OO { - Object o1, o2, o3, o4; - } - final OO oo = new OO(); - oo.o1 = o1; - oo.o2 = o2; - oo.o3 = o1; - oo.o4 = o2; - OO clone = cloner.deepClone(oo); - assertSame(clone.o1, clone.o3); - assertSame(clone.o2, clone.o4); - - final HashSet h1 = new HashSet<>(); - final HashSet h2 = new HashSet<>(); - oo.o1 = h1; - oo.o2 = h2; - oo.o3 = h1; - oo.o4 = h2; - clone = cloner.deepClone(oo); - assertSame(clone.o1, clone.o3); - assertSame(clone.o2, clone.o4); - assertNotSame(clone.o1, clone.o2); - assertNotSame(clone.o2, clone.o3); - } - - /** - * tests if immutable clone is the same instance - */ - public void testCloneImmutables() { - final String s = "test1"; - final String clone1 = cloner.deepClone(s); - assertSame(s, clone1); - } - - /** - * tests if immutable clone is the same instance - */ - public void testCloneFloat() { - final Float float1 = 8F; - final Float cloned = cloner.deepClone(float1); - assertSame(float1, cloned); - assertEquals(float1, cloned); - } - - /** - * tests if arrays are cloned correctly - */ - public void testCloneArrays() { - final int[] ia = {1, 2, 3}; - final int[] cloned = cloner.deepClone(ia); - assertEquals(ia.length, cloned.length); - for (int i = 0; i < ia.length; i++) { - assertEquals(ia[i], cloned[i]); - } - final double[] da = {1, 2, 3}; - final double[] dcloned = cloner.deepClone(da); - assertEquals(da.length, dcloned.length); - for (int i = 0; i < ia.length; i++) { - assertEquals(da[i], dcloned[i]); - } - } - - private class Simple { - private int x = 1; - private String s = "simple"; - private Complex complex; - - public Complex getComplex() { - return complex; - } - - public void setComplex(final Complex complex) { - this.complex = complex; - } - - public int getX() { - return x; - } - - public void setX(final int x) { - this.x = x; - } - - public String getS() { - return s; - } - - public void setS(final String s) { - this.s = s; - } - - @Override - public boolean equals(final Object obj) { - if (obj instanceof Simple) { - final Simple s = (Simple) obj; - return s.getS().equals(getS()) && s.getX() == getX(); - } - return super.equals(obj); - } - } - - /** - * tests cloning of a simple class - */ - public void testCloneSimple() { - final Simple simple = new Simple(); - simple.setS("x1"); - simple.setX(20); - final Simple clone = cloner.deepClone(simple); - assertEquals(simple.getS(), clone.getS()); - assertSame(simple.getS(), clone.getS()); - assertEquals(simple.getX(), clone.getX()); - simple.setS("x2"); - simple.setX(30); - assertNotSame(simple.getS(), clone.getS()); - assertNotEquals(simple.getS(), clone.getS()); - assertFalse(simple.getX() == clone.getX()); - } - - protected class Complex { - private int x = 1; - private String s = "complex"; - private final List l = new ArrayList<>(); - - public Complex() { - l.add(new Simple()); - final Simple simple = new Simple(); - simple.setS("s2"); - simple.setX(30); - l.add(simple); - simple.setComplex(this); - } - - public int getX() { - return x; - } - - public void setX(final int x) { - this.x = x; - } - - public String getS() { - return s; - } - - public List getL() { - return l; - } - - public void setS(final String s) { - this.s = s; - } - - } - - /** - * test cloning of a complex object graph - */ - public void testCloneComplex() { - final Complex complex = new Complex(); - complex.setS("x1"); - complex.setX(20); - final Complex clone = cloner.deepClone(complex); - assertEquals(complex.getS(), clone.getS()); - assertEquals(complex.getX(), clone.getX()); - assertEquals(complex.getL().size(), clone.getL().size()); - final Simple simple1 = complex.getL().get(0); - final Simple simple2 = complex.getL().get(1); - final Simple simple1Clone = clone.getL().get(0); - final Simple simple2Clone = clone.getL().get(1); - assertNotSame(simple1, simple1Clone); - assertNotSame(simple2, simple2Clone); - assertEquals(simple1, simple1Clone); - assertEquals(simple2, simple2Clone); - } - - public void testShallowClone() { - final Simple simple1 = new Simple(); - final Complex complex = new Complex(); - simple1.setComplex(complex); - simple1.setX(5); - simple1.setS("test"); - - final Simple shallowClone = cloner.shallowClone(simple1); - assertNotSame(simple1, shallowClone); - assertSame(simple1.getComplex(), shallowClone.getComplex()); - assertEquals(simple1.getX(), shallowClone.getX()); - assertEquals(simple1.getS(), shallowClone.getS()); - shallowClone.setX(10); - assertTrue(shallowClone.getX() != simple1.getX()); - shallowClone.setS("x"); - assertTrue(shallowClone.getS() != simple1.getS()); - } - - public void testCloneStack() { - final List lst = new LinkedList<>(); - for (int i = 0; i < 100000; i++) { - lst.add(i); - } - final List clone = cloner.deepClone(lst); - assertEquals(lst.size(), clone.size()); - } - - public void testCloneTreeSet() { - final TreeSet set = new TreeSet<>(); - final DC dc1 = new DC(5); - set.add(dc1); - final DC dc2 = new DC(10); - set.add(dc2); - - assertTrue(set.contains(dc1)); - assertTrue(set.contains(dc2)); - - assertTrue(set.remove(dc1)); - set.add(dc1); - - final TreeSet set2 = cloner.deepClone(set); - - assertTrue(set2.contains(dc1)); - assertTrue(set2.contains(dc2)); - assertTrue(set2.remove(dc1)); - assertEquals(1, set2.size()); - } - - public void testCloneHashSet() { - Set set = new HashSet<>(); - final DC dc1 = new DC(5); - set.add(dc1); - final DC dc2 = new DC(10); - set.add(dc2); - - assertTrue(set.contains(dc1)); - assertTrue(set.contains(dc2)); - - assertTrue(set.remove(dc1)); - set.add(dc1); - - set = cloner.deepClone(set); - - assertTrue(set.contains(dc1)); - assertTrue(set.contains(dc2)); - assertTrue(set.remove(dc1)); - assertEquals(1, set.size()); - } - - public void testCloneStability() { - for (int i = 0; i < 10; i++) { - final Complex complex = new Complex(); - complex.setS("x1"); - complex.setX(20); - final ArrayList l = new ArrayList<>(); - l.add(complex); - final HashSet h1 = new HashSet<>(); - final HashSet h2 = new HashSet<>(); - for (int j = 0; j < 100; j++) { - h1.add(j); - h2.add("string" + j); - h1.add(Calendar.getInstance()); - h2.add(new Date()); - l.add(new Random()); - } - - l.add(h1); - l.add(h2); - final Complex clone = cloner.deepClone(complex); - l.add(clone); - cloner.deepClone(l); - } - } - - public void testArrayListCloning() { - final ArrayList l = new ArrayList<>(); - l.add(Calendar.getInstance()); - l.add(2); - l.add(3); - l.add("kostas"); - - final ArrayList cloned = cloner.deepClone(l); - assertEquals(l.size(), cloned.size()); - for (int i = 0; i < l.size(); i++) { - assertEquals(l.get(i), cloned.get(i)); - } - assertNotSame(l, cloned); - assertNotSame(l.get(0), cloned.get(0)); - assertSame(l.get(1), cloned.get(1)); - - l.add(5); - assertEquals(4, cloned.size()); - cloned.add(8); - assertEquals(5, l.size()); - } - - public void testLinkedListCloning() { - final LinkedList l = new LinkedList<>(); - l.add(Calendar.getInstance()); - l.add(2); - l.add(3); - l.add("kostas"); - - final LinkedList cloned = cloner.deepClone(l); - assertEquals(l.size(), cloned.size()); - for (int i = 0; i < l.size(); i++) { - assertEquals(l.get(i), cloned.get(i)); - } - assertNotSame(l, cloned); - assertNotSame(l.get(0), cloned.get(0)); - assertSame(l.get(1), cloned.get(1)); - - l.add(5); - assertEquals(4, cloned.size()); - cloned.add(8); - assertEquals(5, l.size()); - } - - public void testHashSetCloning() { - final HashSet l = new HashSet<>(); - l.add(Calendar.getInstance()); - l.add(2); - l.add(3); - l.add("kostas"); - - final HashSet cloned = cloner.deepClone(l); - assertNotSame(l, cloned); - assertEquals(l.size(), cloned.size()); - for (final Object o : l) { - assertTrue(cloned.contains(o)); - } - } - - public void testHashMapCloning() { - final HashMap m = new HashMap<>(); - m.put("kostas", Calendar.getInstance()); - m.put("tina", 500); - m.put("george", "Ah!"); - final HashMap cloned = cloner.deepClone(m); - assertEquals(m.size(), cloned.size()); - for (final Map.Entry e : m.entrySet()) { - assertEquals(e.getValue(), cloned.get(e.getKey())); - } - assertNotSame(m, cloned); - assertNotSame(m.get("kostas"), cloned.get("kostas")); - assertSame(m.get("tina"), cloned.get("tina")); - cloned.put("x", 100); - assertEquals(3, m.size()); - assertEquals(4, cloned.size()); - } - - public void testTreeMapCloning() { - final TreeMap m = new TreeMap<>(); - m.put("kostas", Calendar.getInstance()); - m.put("tina", 500); - m.put("george", "Ah!"); - final TreeMap cloned = cloner.deepClone(m); - assertEquals(m.size(), cloned.size()); - for (final Map.Entry e : m.entrySet()) { - assertEquals(e.getValue(), cloned.get(e.getKey())); - } - assertNotSame(m, cloned); - assertNotSame(m.get("kostas"), cloned.get("kostas")); - assertSame(m.get("tina"), cloned.get("tina")); - cloned.put("x", 100); - assertEquals(3, m.size()); - assertEquals(4, cloned.size()); - } - - public void testTransientNullPositive() { - final Cloner c = new Cloner(); - c.setNullTransient(true); - final TransientTest tt = new TransientTest(); - final TransientTest deepClone = c.deepClone(tt); - assertNull(deepClone.tr1); - assertNull(deepClone.a); - assertEquals(0, deepClone.i); - assertNotNull(deepClone.nontr); - } - - public void testTransientNullNegative() { - final Cloner c = new Cloner(); - c.setNullTransient(false); - final TransientTest tt = new TransientTest(); - final TransientTest deepClone = c.deepClone(tt); - assertNotNull(deepClone.tr1); - assertNotNull(deepClone.a); - assertNotNull(deepClone.nontr); - } - - public void testNullInsteadOfClone() { - final Cloner c = new Cloner(); - c.nullInsteadOfClone(A.class); - - G g = new G(new A(), new B()); - G deepClone = c.deepClone(g); - - assertNotNull(deepClone.getB()); - assertNull(deepClone.getA()); - } - - public void testNullInsteadOfCloneAnnotatedFields() { - final Cloner c = new Cloner(); - c.nullInsteadOfCloneFieldAnnotation(TestAnnotation.class); - - E e = new E(); - E deepClone = c.deepClone(e); - - assertNotNull(deepClone.getA()); - assertNotSame(e.getA(), deepClone.getA()); - assertNull(deepClone.getId()); - } - - public void testCopyPropertiesArrayPrimitive() { - final int[] src = new int[]{5, 6, 7}; - final int[] dest = new int[3]; - cloner.copyPropertiesOfInheritedClass(src, dest); - assertEquals(src[0], dest[0]); - assertEquals(src[1], dest[1]); - assertEquals(src[2], dest[2]); - } - - public void testCopyPropertiesArray() { - final Object[] src = new Object[]{5, 8.5f, 3.5d}; - final Object[] dest = new Object[3]; - cloner.copyPropertiesOfInheritedClass(src, dest); - assertEquals(src[0], dest[0]); - assertEquals(src[1], dest[1]); - assertEquals(src[2], dest[2]); - } - - public void testCopyPropertiesInheritedClasses() { - final A a = new A(); - final B b = new B(); - b.setName("x"); - b.setX(-1); - b.setY(10); - cloner.copyPropertiesOfInheritedClass(a, b); - - assertEquals("kostas", b.getName()); - assertEquals(5, b.getX()); - assertEquals(10, b.getY()); - } - - public void testFreezable() { - final F f = new F(); - assertNotSame(f, cloner.deepClone(f)); - f.setFrozen(true); - assertSame(f, cloner.deepClone(f)); - } - - public void testDeepCloneDontCloneInstances() { - final A a = new A(); - final B b = new B(); - final G g = new G(a, b); - final G cga = cloner.deepCloneDontCloneInstances(g, a); - assertNotSame(g, cga); - assertNotSame(cga.getB(), b); - assertSame(cga.getA(), a); - - final G cgab = cloner.deepCloneDontCloneInstances(g, a, b); - assertNotSame(g, cgab); - assertSame(cgab.getB(), b); - assertSame(cgab.getA(), a); - } - - static class SynthOuter { - public Inner getInner() { - return new Inner(); - } - - class Inner { - Object x = new Object(); - - public SynthOuter getOuter() { - return SynthOuter.this; - } - } - } - - public void testDontCloneSynthetic() { - final Cloner cloner = new Cloner(); - cloner.setCloneSynthetics(false); - final SynthOuter outer = new SynthOuter(); - final Inner inner = outer.getInner(); - final Inner clonedInner = cloner.deepClone(inner); - assertNotSame(inner, clonedInner); - assertNotSame(inner.x, clonedInner.x); - assertSame(outer, clonedInner.getOuter()); - } - - public void testTreeMapWithComparator() { - final TreeMap m = new TreeMap<>(Comparator.comparingInt(Object::hashCode)); - m.put(new Object() { - @Override - public int hashCode() { - return 1; - } - }, "1"); - m.put(new Object() { - @Override - public int hashCode() { - return 2; - } - }, "2"); - - final TreeMap clone = cloner.deepClone(m); - assertEquals(m, clone); - } - - public void testTreeSetWithComparator() { - final TreeSet set = new TreeSet<>(Comparator.comparingInt(Object::hashCode)); - - set.add(new Object() { - @Override - public int hashCode() { - return 1; - } - }); - set.add(new Object() { - @Override - public int hashCode() { - return 2; - } - }); - - final TreeSet clone = cloner.deepClone(set); - assertEquals(set, clone); - } - - public void testEnumIssue9() { - final TestEnum original = TestEnum.A; - final TestEnum clone = cloner.deepClone(original); - assertSame(clone, original); - } - - public void testDate() { - Date original = new Date(); - Cloner cloner = new Cloner(); - cloner.setNullTransient(true); - Date clone = cloner.deepClone(original); - - // I expect this to be true, but is is false. - assertEquals(0, clone.getTime()); - } - - public void testUnregisterFastCloner() { - Cloner cloner = new Cloner(); - cloner.unregisterFastCloner(HashMap.class); - cloner.registerFastCloner(HashMap.class, new FastClonerHashMap()); - } - - public void testEmptyLinkedHashMap() { - LinkedHashMap m = new LinkedHashMap<>(); - LinkedHashMap cloned = cloner.deepClone(m); - assertEquals(m, cloned); - } - - public void testLinkedHashMap() { - LinkedHashMap m = new LinkedHashMap<>(); - for (int i = 1; i < 10000; i++) { - m.put(i, i * 2); - } - LinkedHashMap cloned = cloner.deepClone(m); - assertEquals(m, cloned); - } - - public void testLinkedHashMapIterationOrder() { - LinkedHashMap m = new LinkedHashMap<>(); - for (int i = 1000; i >= 1; i--) { - m.put(i, i * 2); - } - LinkedHashMap cloned = cloner.deepClone(m); - Iterator it = cloned.keySet().iterator(); - for (int i = 1000; i >= 1; i--) { - assertEquals((Integer) i, it.next()); - } - } - - public void testCloneArrayListSubList() { - List a = new ArrayList<>(); - a.add("1"); - a.add("2"); - a.add("3"); - - List b = a.subList(0, 1); - - b.add("3"); - b.remove(0); - - b.size(); // fine - - assertEquals(1, cloner.deepClone(b).size()); // throws ConcurrentModificationException - } - - public void testCloneLinkedListSubList() { - List a = new LinkedList<>(); - a.add("1"); - a.add("2"); - a.add("3"); - - List b = a.subList(0, 1); - - b.add("3"); - b.remove(0); - - b.size(); // fine - - List clone = cloner.deepClone(b); - assertEquals(1, clone.size()); - } - -// public void testHashMapIterator() { -// HashMap m = new HashMap(); -// m.put(1, "one"); -// m.put(2, "two"); -// -// Iterator> it = m.entrySet().iterator(); -// m.put(3, "three"); -// -// Iterator> cIt = cloner.deepClone(it); -// cIt.next(); // throws ConcurrentModificationException -// } - - public void testConcurrentLinkedQueue() { - ConcurrentLinkedQueue list = new ConcurrentLinkedQueue<>(); - for (int i = 0; i < 3000; ++i) { - A a = new A(); - a.setX(i); - list.add(a); - } - ConcurrentLinkedQueue cloned = cloner.deepClone(list);// StackOverflowError - Assert.assertArrayEquals(list.toArray(), cloned.toArray()); - assertNotSame(list, cloned); - assertNotSame(list.peek(), cloned.peek()); - } - - /** - * Test case with EnumMap where one Enum is mapped onto null - */ - public void testEnumMapWithNullValue() { - EnumMap originalMap = new EnumMap<>(TestEnum.class); - originalMap.put(TestEnum.A, null); - - EnumMap clonedMap = cloner.deepClone(originalMap); - assertNotSame("Cloned EnumMap same as original EnumMap", originalMap, clonedMap); - assertEquals("Cloned Map not of expected size", 1, clonedMap.size()); - assertNull("Expected value is null (contains key A)", clonedMap.get(TestEnum.A)); - assertNull("Expected value is null (doesn't contain key B)", clonedMap.get(TestEnum.B)); - assertTrue("Cloned Map doesn't contain key A", clonedMap.containsKey(TestEnum.A)); - assertEquals("Cloned EnumMap not equal to original EnumMap", originalMap, clonedMap); - } - - /** - * Test case for an empty EnumMap - */ - public void testEmptyEnumMap() { - EnumMap originalMap = new EnumMap<>(TestEnum.class); - EnumMap clonedMap = cloner.deepClone(originalMap); - assertNotSame("Cloned EnumMap same as original EnumMap", originalMap, clonedMap); - assertEquals("Cloned Map is not empty", 0, clonedMap.size()); - assertTrue("Cloned Map is not empty", clonedMap.isEmpty()); - assertEquals("Cloned EnumMap not equal to original EnumMap", originalMap, clonedMap); - } - - - /** - * Test case for non empty EnumMap - */ - public void testEnumMapWithNonNullValue() { - EnumMap originalMap = new EnumMap<>(TestEnum.class); - originalMap.put(TestEnum.A, "Hello"); - EnumMap clonedMap = cloner.deepClone(originalMap); - assertNotSame("Cloned EnumMap same as original EnumMap", originalMap, clonedMap); - assertEquals("Cloned EnumMap not equal to original EnumMap", originalMap, clonedMap); - assertEquals("Cloned EnumMap value not equal to original EnumMap", originalMap.get(TestEnum.A), clonedMap.get(TestEnum.A)); - } - - /** - * Test case for EnumMap with non-null mutable value - * to see if it is deep cloned - */ - public void testEnumMapWithNonNullMutableValue() { - EnumMap originalMap = new EnumMap<>(TestEnum.class); - DC dc = new DC(5); - originalMap.put(TestEnum.A, dc); - EnumMap clonedMap = cloner.deepClone(originalMap); - assertNotSame("Cloned EnumMap same as original EnumMap", originalMap, clonedMap); - assertEquals("Cloned EnumMap not equal to original EnumMap", originalMap, clonedMap); - - DC dc2 = clonedMap.get(TestEnum.A); - // Assert references are different - assertNotSame("value not cloned", dc, dc2); - // Assert both objects are equal - assertEquals("Cloned value not equal to original object", dc, dc2); - - } - - /** - * Test case for cloning LinkedHashSet - */ - public void testLinkedHashSetToArray() { - Set set = new LinkedHashSet<>(); - set.add(new Object()); - set.add(new Object()); - - Set clonedSet = cloner.deepClone(set); - assertTrue("Cloned LinkedHashSet not instanceof LinkedHashSet", clonedSet instanceof LinkedHashSet); - - - Object first = clonedSet.toArray()[0]; - assertTrue("First element not contained in cloned LinkedHashSet", clonedSet.contains(first)); - assertTrue("First element not removed from LinkedHashSet", clonedSet.remove(first)); - } - - /** - * Another test case for LinkedHashSet - */ - public void testLinkedHashSetEquals() { - LinkedHashSet originalSet = new LinkedHashSet<>(); - originalSet.add("Test 1"); - originalSet.add("Test 2"); - - LinkedHashSet clonedSet = cloner.deepClone(originalSet); - assertNotSame("Cloned LinkedHashSet same as original one", originalSet, clonedSet); - assertEquals("Cloned LinkedHashSet not equal to original one", originalSet, clonedSet); - } - - - /** - * Test if insertion order of LinkedhashSet is the same - */ - public void testLinkedHashSetInserationOrder() { - LinkedHashSet originalSet = new LinkedHashSet<>(); - for (int i = 1000; i >= 1; i--) { - originalSet.add(i); - } - - LinkedHashSet clonedSet = cloner.deepClone(originalSet); - assertEquals("Cloned LinkedHashSet not equal to original one", originalSet, clonedSet); - int i = 1000; - for (Integer act : clonedSet) { - assertEquals("LinkedHashSet iteration order not preserved", i--, act.intValue()); - } - } - - /** - * Tests if LinkedHashSet with mutable value is deep cloned - */ - public void testLinkedHashSetWithMutableValue() { - LinkedHashSet originalSet = new LinkedHashSet<>(); - DC dc = new DC(1000); - originalSet.add(dc); - - LinkedHashSet clonedSet = cloner.deepClone(originalSet); - assertEquals("Size of cloned LinkedHashSet is wrong", 1, clonedSet.size()); - assertNotSame("Cloned LinkedHashSet same as original one", originalSet, clonedSet); - assertEquals("Cloned LinkedHashSet not equal to original one", originalSet, clonedSet); - DC dc2 = clonedSet.iterator().next(); - // Assert references are different - assertNotSame("value not cloned", dc, dc2); - // Assert both objects are equal - assertEquals("Cloned value not equal to original object", dc, dc2); - - } - - public void testStaticTransient() { - class StaticTransient extends ArrayList { - } - - cloner.deepClone(new StaticTransient()); - } -} - +package com.rits.tests.cloning; + +import com.rits.cloning.Cloner; +import com.rits.cloning.FastClonerHashMap; +import com.rits.cloning.Immutable; +import com.rits.tests.cloning.TestCloner.SynthOuter.Inner; +import com.rits.tests.cloning.domain.*; +import junit.framework.TestCase; +import org.junit.Assert; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; +import java.util.*; +import java.util.concurrent.ConcurrentLinkedQueue; + +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; +import static org.junit.Assert.assertNotEquals; + +/** + * @author kostantinos.kougios + *

+ * 18 Sep 2008 + */ +public class TestCloner extends TestCase { + private final Cloner cloner = new Cloner(); + + { + cloner.setDumpClonedClasses(false); + } + + @Target(TYPE) + @Retention(RUNTIME) + private @interface MyImmutable { + + } + + @MyImmutable + static private class MyAX { + } + + public void testCloneListOf12() { + List list1 = List.of(1); + Assert.assertEquals(list1, cloner.deepClone(list1)); + Assert.assertEquals(1, cloner.deepClone(list1).size()); + List list2 = List.of(1, 2); + Assert.assertEquals(list2, cloner.deepClone(list2)); + Assert.assertEquals(2, cloner.deepClone(list2).size()); + } + + public void testCloneSetOf12() { + Set set1 = Set.of(1); + Assert.assertEquals(set1, cloner.deepClone(set1)); + Assert.assertEquals(1, cloner.deepClone(set1).size()); + Set set2 = Set.of(1, 2); + Assert.assertEquals(set2, cloner.deepClone(set2)); + Assert.assertEquals(2, cloner.deepClone(set2).size()); + } + + public void testCalendarTimezone() { + TimeZone timeZone = TimeZone.getTimeZone("America/Los_Angeles"); + Calendar c = Calendar.getInstance(timeZone); + Calendar cloned = cloner.deepClone(c); + assertEquals(timeZone, cloned.getTimeZone()); + } + + public void testCloneEnumInMapIssue20() { + Map m = new HashMap<>(); + m.put(1, TestEnum.A); + m.put(2, TestEnum.B); + m.put(3, TestEnum.C); + Map clone = cloner.deepClone(m); + + assertSame(clone.get(1), TestEnum.A); + assertSame(clone.get(2), TestEnum.B); + assertSame(clone.get(3), TestEnum.C); + } + + public void testCustomAnnotation() { + final Cloner cloner = new Cloner() { + @Override + protected Class getImmutableAnnotation() { + return MyImmutable.class; + } + }; + final MyAX o = new MyAX(); + final MyAX c = cloner.deepClone(o); + assertSame(o, c); + } + + public void testConsiderImmutable() { + final Cloner cloner = new Cloner() { + @Override + protected boolean considerImmutable(final Class clz) { + return clz == Object.class; + } + }; + final Object o = new Object(); + final Object c = cloner.deepClone(o); + assertSame(o, c); + } + + class X { + private X(int x) { + x = 5; + } + } + + @Immutable(subClass = true) + static public class ATestImmutable { + } + + static public class ATestImmutableSubclass extends ATestImmutable { + + } + + @Immutable + static public class BTestImmutable { + } + + static public class BTestImmutableSubclass extends BTestImmutable { + } + + public void testIssue7() { + final HashMap source = new HashMap<>(); + source.put("string", "string"); + source.put("array", new Integer[]{1, 2, 3}); + final HashMap sc = cloner.shallowClone(source); + assertEquals("string", sc.get("string")); + } + + public void testIgnoreInstanceOf() { + final Cloner cloner = new Cloner(); + cloner.dontCloneInstanceOf(A.class); + + final A a = new A() { + }; + assertNotSame(a.getClass(), A.class); + assertSame(a, cloner.deepClone(a)); + } + + public void testImmutableSubclassNotEnabled() { + final BTestImmutableSubclass a = new BTestImmutableSubclass(); + final BTestImmutableSubclass ca = cloner.deepClone(a); + assertNotSame(a, ca); + } + + public void testImmutableSubclass() { + final ATestImmutableSubclass a = new ATestImmutableSubclass(); + assertSame(a, cloner.deepClone(a)); + assertSame(a, cloner.deepClone(a)); + } + + public void testImmutable() { + final ATestImmutable a = new ATestImmutable(); + assertSame(a, cloner.deepClone(a)); + assertSame(a, cloner.deepClone(a)); + } + + /** + * tests if it happens that in the deep-graph of the cloned objects, + * if a reference to the same object exists twice, the cloned object + * will have only 1 clone and references to this clone. + */ + public void testCloningOfSameObject() { + final Object o1 = new Object(); + final Object o2 = new Object(); + class OO { + Object o1, o2, o3, o4; + } + final OO oo = new OO(); + oo.o1 = o1; + oo.o2 = o2; + oo.o3 = o1; + oo.o4 = o2; + OO clone = cloner.deepClone(oo); + assertSame(clone.o1, clone.o3); + assertSame(clone.o2, clone.o4); + + final HashSet h1 = new HashSet<>(); + final HashSet h2 = new HashSet<>(); + oo.o1 = h1; + oo.o2 = h2; + oo.o3 = h1; + oo.o4 = h2; + clone = cloner.deepClone(oo); + assertSame(clone.o1, clone.o3); + assertSame(clone.o2, clone.o4); + assertNotSame(clone.o1, clone.o2); + assertNotSame(clone.o2, clone.o3); + } + + /** + * tests if immutable clone is the same instance + */ + public void testCloneImmutables() { + final String s = "test1"; + final String clone1 = cloner.deepClone(s); + assertSame(s, clone1); + } + + /** + * tests if immutable clone is the same instance + */ + public void testCloneFloat() { + final Float float1 = 8F; + final Float cloned = cloner.deepClone(float1); + assertSame(float1, cloned); + assertEquals(float1, cloned); + } + + /** + * tests if arrays are cloned correctly + */ + public void testCloneArrays() { + final int[] ia = {1, 2, 3}; + final int[] cloned = cloner.deepClone(ia); + assertEquals(ia.length, cloned.length); + for (int i = 0; i < ia.length; i++) { + assertEquals(ia[i], cloned[i]); + } + final double[] da = {1, 2, 3}; + final double[] dcloned = cloner.deepClone(da); + assertEquals(da.length, dcloned.length); + for (int i = 0; i < ia.length; i++) { + assertEquals(da[i], dcloned[i]); + } + } + + private class Simple { + private int x = 1; + private String s = "simple"; + private Complex complex; + + public Complex getComplex() { + return complex; + } + + public void setComplex(final Complex complex) { + this.complex = complex; + } + + public int getX() { + return x; + } + + public void setX(final int x) { + this.x = x; + } + + public String getS() { + return s; + } + + public void setS(final String s) { + this.s = s; + } + + @Override + public boolean equals(final Object obj) { + if (obj instanceof Simple) { + final Simple s = (Simple) obj; + return s.getS().equals(getS()) && s.getX() == getX(); + } + return super.equals(obj); + } + } + + /** + * tests cloning of a simple class + */ + public void testCloneSimple() { + final Simple simple = new Simple(); + simple.setS("x1"); + simple.setX(20); + final Simple clone = cloner.deepClone(simple); + assertEquals(simple.getS(), clone.getS()); + assertSame(simple.getS(), clone.getS()); + assertEquals(simple.getX(), clone.getX()); + simple.setS("x2"); + simple.setX(30); + assertNotSame(simple.getS(), clone.getS()); + assertNotEquals(simple.getS(), clone.getS()); + assertFalse(simple.getX() == clone.getX()); + } + + protected class Complex { + private int x = 1; + private String s = "complex"; + private final List l = new ArrayList<>(); + + public Complex() { + l.add(new Simple()); + final Simple simple = new Simple(); + simple.setS("s2"); + simple.setX(30); + l.add(simple); + simple.setComplex(this); + } + + public int getX() { + return x; + } + + public void setX(final int x) { + this.x = x; + } + + public String getS() { + return s; + } + + public List getL() { + return l; + } + + public void setS(final String s) { + this.s = s; + } + + } + + /** + * test cloning of a complex object graph + */ + public void testCloneComplex() { + final Complex complex = new Complex(); + complex.setS("x1"); + complex.setX(20); + final Complex clone = cloner.deepClone(complex); + assertEquals(complex.getS(), clone.getS()); + assertEquals(complex.getX(), clone.getX()); + assertEquals(complex.getL().size(), clone.getL().size()); + final Simple simple1 = complex.getL().get(0); + final Simple simple2 = complex.getL().get(1); + final Simple simple1Clone = clone.getL().get(0); + final Simple simple2Clone = clone.getL().get(1); + assertNotSame(simple1, simple1Clone); + assertNotSame(simple2, simple2Clone); + assertEquals(simple1, simple1Clone); + assertEquals(simple2, simple2Clone); + } + + public void testShallowClone() { + final Simple simple1 = new Simple(); + final Complex complex = new Complex(); + simple1.setComplex(complex); + simple1.setX(5); + simple1.setS("test"); + + final Simple shallowClone = cloner.shallowClone(simple1); + assertNotSame(simple1, shallowClone); + assertSame(simple1.getComplex(), shallowClone.getComplex()); + assertEquals(simple1.getX(), shallowClone.getX()); + assertEquals(simple1.getS(), shallowClone.getS()); + shallowClone.setX(10); + assertTrue(shallowClone.getX() != simple1.getX()); + shallowClone.setS("x"); + assertTrue(shallowClone.getS() != simple1.getS()); + } + + public void testCloneStack() { + final List lst = new LinkedList<>(); + for (int i = 0; i < 100000; i++) { + lst.add(i); + } + final List clone = cloner.deepClone(lst); + assertEquals(lst.size(), clone.size()); + } + + public void testCloneTreeSet() { + final TreeSet set = new TreeSet<>(); + final DC dc1 = new DC(5); + set.add(dc1); + final DC dc2 = new DC(10); + set.add(dc2); + + assertTrue(set.contains(dc1)); + assertTrue(set.contains(dc2)); + + assertTrue(set.remove(dc1)); + set.add(dc1); + + final TreeSet set2 = cloner.deepClone(set); + + assertTrue(set2.contains(dc1)); + assertTrue(set2.contains(dc2)); + assertTrue(set2.remove(dc1)); + assertEquals(1, set2.size()); + } + + public void testCloneHashSet() { + Set set = new HashSet<>(); + final DC dc1 = new DC(5); + set.add(dc1); + final DC dc2 = new DC(10); + set.add(dc2); + + assertTrue(set.contains(dc1)); + assertTrue(set.contains(dc2)); + + assertTrue(set.remove(dc1)); + set.add(dc1); + + set = cloner.deepClone(set); + + assertTrue(set.contains(dc1)); + assertTrue(set.contains(dc2)); + assertTrue(set.remove(dc1)); + assertEquals(1, set.size()); + } + + public void testCloneStability() { + for (int i = 0; i < 10; i++) { + final Complex complex = new Complex(); + complex.setS("x1"); + complex.setX(20); + final ArrayList l = new ArrayList<>(); + l.add(complex); + final HashSet h1 = new HashSet<>(); + final HashSet h2 = new HashSet<>(); + for (int j = 0; j < 100; j++) { + h1.add(j); + h2.add("string" + j); + h1.add(Calendar.getInstance()); + h2.add(new Date()); + l.add(new Random()); + } + + l.add(h1); + l.add(h2); + final Complex clone = cloner.deepClone(complex); + l.add(clone); + cloner.deepClone(l); + } + } + + public void testArrayListCloning() { + final ArrayList l = new ArrayList<>(); + l.add(Calendar.getInstance()); + l.add(2); + l.add(3); + l.add("kostas"); + + final ArrayList cloned = cloner.deepClone(l); + assertEquals(l.size(), cloned.size()); + for (int i = 0; i < l.size(); i++) { + assertEquals(l.get(i), cloned.get(i)); + } + assertNotSame(l, cloned); + assertNotSame(l.get(0), cloned.get(0)); + assertSame(l.get(1), cloned.get(1)); + + l.add(5); + assertEquals(4, cloned.size()); + cloned.add(8); + assertEquals(5, l.size()); + } + + public void testLinkedListCloning() { + final LinkedList l = new LinkedList<>(); + l.add(Calendar.getInstance()); + l.add(2); + l.add(3); + l.add("kostas"); + + final LinkedList cloned = cloner.deepClone(l); + assertEquals(l.size(), cloned.size()); + for (int i = 0; i < l.size(); i++) { + assertEquals(l.get(i), cloned.get(i)); + } + assertNotSame(l, cloned); + assertNotSame(l.get(0), cloned.get(0)); + assertSame(l.get(1), cloned.get(1)); + + l.add(5); + assertEquals(4, cloned.size()); + cloned.add(8); + assertEquals(5, l.size()); + } + + public void testHashSetCloning() { + final HashSet l = new HashSet<>(); + l.add(Calendar.getInstance()); + l.add(2); + l.add(3); + l.add("kostas"); + + final HashSet cloned = cloner.deepClone(l); + assertNotSame(l, cloned); + assertEquals(l.size(), cloned.size()); + for (final Object o : l) { + assertTrue(cloned.contains(o)); + } + } + + public void testHashMapCloning() { + final HashMap m = new HashMap<>(); + m.put("kostas", Calendar.getInstance()); + m.put("tina", 500); + m.put("george", "Ah!"); + final HashMap cloned = cloner.deepClone(m); + assertEquals(m.size(), cloned.size()); + for (final Map.Entry e : m.entrySet()) { + assertEquals(e.getValue(), cloned.get(e.getKey())); + } + assertNotSame(m, cloned); + assertNotSame(m.get("kostas"), cloned.get("kostas")); + assertSame(m.get("tina"), cloned.get("tina")); + cloned.put("x", 100); + assertEquals(3, m.size()); + assertEquals(4, cloned.size()); + } + + public void testTreeMapCloning() { + final TreeMap m = new TreeMap<>(); + m.put("kostas", Calendar.getInstance()); + m.put("tina", 500); + m.put("george", "Ah!"); + final TreeMap cloned = cloner.deepClone(m); + assertEquals(m.size(), cloned.size()); + for (final Map.Entry e : m.entrySet()) { + assertEquals(e.getValue(), cloned.get(e.getKey())); + } + assertNotSame(m, cloned); + assertNotSame(m.get("kostas"), cloned.get("kostas")); + assertSame(m.get("tina"), cloned.get("tina")); + cloned.put("x", 100); + assertEquals(3, m.size()); + assertEquals(4, cloned.size()); + } + + public void testTransientNullPositive() { + final Cloner c = new Cloner(); + c.setNullTransient(true); + final TransientTest tt = new TransientTest(); + final TransientTest deepClone = c.deepClone(tt); + assertNull(deepClone.tr1); + assertNull(deepClone.a); + assertEquals(0, deepClone.i); + assertNotNull(deepClone.nontr); + } + + public void testTransientNullNegative() { + final Cloner c = new Cloner(); + c.setNullTransient(false); + final TransientTest tt = new TransientTest(); + final TransientTest deepClone = c.deepClone(tt); + assertNotNull(deepClone.tr1); + assertNotNull(deepClone.a); + assertNotNull(deepClone.nontr); + } + + public void testNullInsteadOfClone() { + final Cloner c = new Cloner(); + c.nullInsteadOfClone(A.class); + + G g = new G(new A(), new B()); + G deepClone = c.deepClone(g); + + assertNotNull(deepClone.getB()); + assertNull(deepClone.getA()); + } + + public void testNullInsteadOfCloneAnnotatedFields() { + final Cloner c = new Cloner(); + c.nullInsteadOfCloneFieldAnnotation(TestAnnotation.class); + + E e = new E(); + E deepClone = c.deepClone(e); + + assertNotNull(deepClone.getA()); + assertNotSame(e.getA(), deepClone.getA()); + assertNull(deepClone.getId()); + } + + public void testCopyPropertiesArrayPrimitive() { + final int[] src = new int[]{5, 6, 7}; + final int[] dest = new int[3]; + cloner.copyPropertiesOfInheritedClass(src, dest); + assertEquals(src[0], dest[0]); + assertEquals(src[1], dest[1]); + assertEquals(src[2], dest[2]); + } + + public void testCopyPropertiesArray() { + final Object[] src = new Object[]{5, 8.5f, 3.5d}; + final Object[] dest = new Object[3]; + cloner.copyPropertiesOfInheritedClass(src, dest); + assertEquals(src[0], dest[0]); + assertEquals(src[1], dest[1]); + assertEquals(src[2], dest[2]); + } + + public void testCopyPropertiesInheritedClasses() { + final A a = new A(); + final B b = new B(); + b.setName("x"); + b.setX(-1); + b.setY(10); + cloner.copyPropertiesOfInheritedClass(a, b); + + assertEquals("kostas", b.getName()); + assertEquals(5, b.getX()); + assertEquals(10, b.getY()); + } + + public void testFreezable() { + final F f = new F(); + assertNotSame(f, cloner.deepClone(f)); + f.setFrozen(true); + assertSame(f, cloner.deepClone(f)); + } + + public void testDeepCloneDontCloneInstances() { + final A a = new A(); + final B b = new B(); + final G g = new G(a, b); + final G cga = cloner.deepCloneDontCloneInstances(g, a); + assertNotSame(g, cga); + assertNotSame(cga.getB(), b); + assertSame(cga.getA(), a); + + final G cgab = cloner.deepCloneDontCloneInstances(g, a, b); + assertNotSame(g, cgab); + assertSame(cgab.getB(), b); + assertSame(cgab.getA(), a); + } + + static class SynthOuter { + public Inner getInner() { + return new Inner(); + } + + class Inner { + Object x = new Object(); + + public SynthOuter getOuter() { + return SynthOuter.this; + } + } + } + + public void testDontCloneSynthetic() { + final Cloner cloner = new Cloner(); + cloner.setCloneSynthetics(false); + final SynthOuter outer = new SynthOuter(); + final Inner inner = outer.getInner(); + final Inner clonedInner = cloner.deepClone(inner); + assertNotSame(inner, clonedInner); + assertNotSame(inner.x, clonedInner.x); + assertSame(outer, clonedInner.getOuter()); + } + + public void testTreeMapWithComparator() { + final TreeMap m = new TreeMap<>(Comparator.comparingInt(Object::hashCode)); + m.put(new Object() { + @Override + public int hashCode() { + return 1; + } + }, "1"); + m.put(new Object() { + @Override + public int hashCode() { + return 2; + } + }, "2"); + + final TreeMap clone = cloner.deepClone(m); + assertEquals(m, clone); + } + + public void testTreeSetWithComparator() { + final TreeSet set = new TreeSet<>(Comparator.comparingInt(Object::hashCode)); + + set.add(new Object() { + @Override + public int hashCode() { + return 1; + } + }); + set.add(new Object() { + @Override + public int hashCode() { + return 2; + } + }); + + final TreeSet clone = cloner.deepClone(set); + assertEquals(set, clone); + } + + public void testEnumIssue9() { + final TestEnum original = TestEnum.A; + final TestEnum clone = cloner.deepClone(original); + assertSame(clone, original); + } + + public void testDate() { + Date original = new Date(); + Cloner cloner = new Cloner(); + cloner.setNullTransient(true); + Date clone = cloner.deepClone(original); + + // I expect this to be true, but is is false. + assertEquals(0, clone.getTime()); + } + + public void testUnregisterFastCloner() { + Cloner cloner = new Cloner(); + cloner.unregisterFastCloner(HashMap.class); + cloner.registerFastCloner(HashMap.class, new FastClonerHashMap()); + } + + public void testEmptyLinkedHashMap() { + LinkedHashMap m = new LinkedHashMap<>(); + LinkedHashMap cloned = cloner.deepClone(m); + assertEquals(m, cloned); + } + + public void testLinkedHashMap() { + LinkedHashMap m = new LinkedHashMap<>(); + for (int i = 1; i < 10000; i++) { + m.put(i, i * 2); + } + LinkedHashMap cloned = cloner.deepClone(m); + assertEquals(m, cloned); + } + + public void testLinkedHashMapIterationOrder() { + LinkedHashMap m = new LinkedHashMap<>(); + for (int i = 1000; i >= 1; i--) { + m.put(i, i * 2); + } + LinkedHashMap cloned = cloner.deepClone(m); + Iterator it = cloned.keySet().iterator(); + for (int i = 1000; i >= 1; i--) { + assertEquals((Integer) i, it.next()); + } + } + + public void testCloneArrayListSubList() { + List a = new ArrayList<>(); + a.add("1"); + a.add("2"); + a.add("3"); + + List b = a.subList(0, 1); + + b.add("3"); + b.remove(0); + + b.size(); // fine + + assertEquals(1, cloner.deepClone(b).size()); // throws ConcurrentModificationException + } + + public void testCloneLinkedListSubList() { + List a = new LinkedList<>(); + a.add("1"); + a.add("2"); + a.add("3"); + + List b = a.subList(0, 1); + + b.add("3"); + b.remove(0); + + b.size(); // fine + + List clone = cloner.deepClone(b); + assertEquals(1, clone.size()); + } + +// public void testHashMapIterator() { +// HashMap m = new HashMap(); +// m.put(1, "one"); +// m.put(2, "two"); +// +// Iterator> it = m.entrySet().iterator(); +// m.put(3, "three"); +// +// Iterator> cIt = cloner.deepClone(it); +// cIt.next(); // throws ConcurrentModificationException +// } + + public void testConcurrentLinkedQueue() { + ConcurrentLinkedQueue list = new ConcurrentLinkedQueue<>(); + for (int i = 0; i < 3000; ++i) { + A a = new A(); + a.setX(i); + list.add(a); + } + ConcurrentLinkedQueue cloned = cloner.deepClone(list);// StackOverflowError + Assert.assertArrayEquals(list.toArray(), cloned.toArray()); + assertNotSame(list, cloned); + assertNotSame(list.peek(), cloned.peek()); + } + + /** + * Test case with EnumMap where one Enum is mapped onto null + */ + public void testEnumMapWithNullValue() { + EnumMap originalMap = new EnumMap<>(TestEnum.class); + originalMap.put(TestEnum.A, null); + + EnumMap clonedMap = cloner.deepClone(originalMap); + assertNotSame("Cloned EnumMap same as original EnumMap", originalMap, clonedMap); + assertEquals("Cloned Map not of expected size", 1, clonedMap.size()); + assertNull("Expected value is null (contains key A)", clonedMap.get(TestEnum.A)); + assertNull("Expected value is null (doesn't contain key B)", clonedMap.get(TestEnum.B)); + assertTrue("Cloned Map doesn't contain key A", clonedMap.containsKey(TestEnum.A)); + assertEquals("Cloned EnumMap not equal to original EnumMap", originalMap, clonedMap); + } + + /** + * Test case for an empty EnumMap + */ + public void testEmptyEnumMap() { + EnumMap originalMap = new EnumMap<>(TestEnum.class); + EnumMap clonedMap = cloner.deepClone(originalMap); + assertNotSame("Cloned EnumMap same as original EnumMap", originalMap, clonedMap); + assertEquals("Cloned Map is not empty", 0, clonedMap.size()); + assertTrue("Cloned Map is not empty", clonedMap.isEmpty()); + assertEquals("Cloned EnumMap not equal to original EnumMap", originalMap, clonedMap); + } + + + /** + * Test case for non empty EnumMap + */ + public void testEnumMapWithNonNullValue() { + EnumMap originalMap = new EnumMap<>(TestEnum.class); + originalMap.put(TestEnum.A, "Hello"); + EnumMap clonedMap = cloner.deepClone(originalMap); + assertNotSame("Cloned EnumMap same as original EnumMap", originalMap, clonedMap); + assertEquals("Cloned EnumMap not equal to original EnumMap", originalMap, clonedMap); + assertEquals("Cloned EnumMap value not equal to original EnumMap", originalMap.get(TestEnum.A), clonedMap.get(TestEnum.A)); + } + + /** + * Test case for EnumMap with non-null mutable value + * to see if it is deep cloned + */ + public void testEnumMapWithNonNullMutableValue() { + EnumMap originalMap = new EnumMap<>(TestEnum.class); + DC dc = new DC(5); + originalMap.put(TestEnum.A, dc); + EnumMap clonedMap = cloner.deepClone(originalMap); + assertNotSame("Cloned EnumMap same as original EnumMap", originalMap, clonedMap); + assertEquals("Cloned EnumMap not equal to original EnumMap", originalMap, clonedMap); + + DC dc2 = clonedMap.get(TestEnum.A); + // Assert references are different + assertNotSame("value not cloned", dc, dc2); + // Assert both objects are equal + assertEquals("Cloned value not equal to original object", dc, dc2); + + } + + /** + * Test case for cloning LinkedHashSet + */ + public void testLinkedHashSetToArray() { + Set set = new LinkedHashSet<>(); + set.add(new Object()); + set.add(new Object()); + + Set clonedSet = cloner.deepClone(set); + assertTrue("Cloned LinkedHashSet not instanceof LinkedHashSet", clonedSet instanceof LinkedHashSet); + + + Object first = clonedSet.toArray()[0]; + assertTrue("First element not contained in cloned LinkedHashSet", clonedSet.contains(first)); + assertTrue("First element not removed from LinkedHashSet", clonedSet.remove(first)); + } + + /** + * Another test case for LinkedHashSet + */ + public void testLinkedHashSetEquals() { + LinkedHashSet originalSet = new LinkedHashSet<>(); + originalSet.add("Test 1"); + originalSet.add("Test 2"); + + LinkedHashSet clonedSet = cloner.deepClone(originalSet); + assertNotSame("Cloned LinkedHashSet same as original one", originalSet, clonedSet); + assertEquals("Cloned LinkedHashSet not equal to original one", originalSet, clonedSet); + } + + + /** + * Test if insertion order of LinkedhashSet is the same + */ + public void testLinkedHashSetInserationOrder() { + LinkedHashSet originalSet = new LinkedHashSet<>(); + for (int i = 1000; i >= 1; i--) { + originalSet.add(i); + } + + LinkedHashSet clonedSet = cloner.deepClone(originalSet); + assertEquals("Cloned LinkedHashSet not equal to original one", originalSet, clonedSet); + int i = 1000; + for (Integer act : clonedSet) { + assertEquals("LinkedHashSet iteration order not preserved", i--, act.intValue()); + } + } + + /** + * Tests if LinkedHashSet with mutable value is deep cloned + */ + public void testLinkedHashSetWithMutableValue() { + LinkedHashSet originalSet = new LinkedHashSet<>(); + DC dc = new DC(1000); + originalSet.add(dc); + + LinkedHashSet clonedSet = cloner.deepClone(originalSet); + assertEquals("Size of cloned LinkedHashSet is wrong", 1, clonedSet.size()); + assertNotSame("Cloned LinkedHashSet same as original one", originalSet, clonedSet); + assertEquals("Cloned LinkedHashSet not equal to original one", originalSet, clonedSet); + DC dc2 = clonedSet.iterator().next(); + // Assert references are different + assertNotSame("value not cloned", dc, dc2); + // Assert both objects are equal + assertEquals("Cloned value not equal to original object", dc, dc2); + + } + + public void testStaticTransient() { + class StaticTransient extends ArrayList { + } + + cloner.deepClone(new StaticTransient()); + } +} + From 75462ff50ca6d04197c51d4580f823d52b54deae Mon Sep 17 00:00:00 2001 From: jia Date: Fri, 23 Jul 2021 15:01:01 +0800 Subject: [PATCH 7/9] feat:FastClonerListOf12 and FastClonerSetOf12 --- src/main/java/com/rits/cloning/Cloner.java | 5 +++++ .../com/rits/cloning/FastClonerListOf12.java | 20 +++++++++++++++++++ .../com/rits/cloning/FastClonerSetOf12.java | 18 +++++++++++++++++ .../com/rits/tests/cloning/TestCloner.java | 8 ++++++++ 4 files changed, 51 insertions(+) create mode 100644 src/main/java/com/rits/cloning/FastClonerListOf12.java create mode 100644 src/main/java/com/rits/cloning/FastClonerSetOf12.java diff --git a/src/main/java/com/rits/cloning/Cloner.java b/src/main/java/com/rits/cloning/Cloner.java index 53b6d9f..1696b02 100644 --- a/src/main/java/com/rits/cloning/Cloner.java +++ b/src/main/java/com/rits/cloning/Cloner.java @@ -5,6 +5,7 @@ import java.lang.annotation.Annotation; import java.lang.reflect.Array; import java.lang.reflect.Field; + import java.lang.reflect.Modifier; import java.math.BigDecimal; import java.math.BigInteger; @@ -113,6 +114,10 @@ protected void registerFastCloners() { registerInaccessibleClassToBeFastCloned("java.util.ArrayList$SubList", subListCloner); registerInaccessibleClassToBeFastCloned("java.util.SubList", subListCloner); registerInaccessibleClassToBeFastCloned("java.util.RandomAccessSubList", subListCloner); + FastClonerListOf12 listOf12 = new FastClonerListOf12(); + registerInaccessibleClassToBeFastCloned("java.util.ImmutableCollections$List12",listOf12); + FastClonerSetOf12 setOf12 = new FastClonerSetOf12(); + registerInaccessibleClassToBeFastCloned("java.util.ImmutableCollections$Set12",setOf12); } protected void registerInaccessibleClassToBeFastCloned(String className, IFastCloner fastCloner) { diff --git a/src/main/java/com/rits/cloning/FastClonerListOf12.java b/src/main/java/com/rits/cloning/FastClonerListOf12.java new file mode 100644 index 0000000..bd56a8f --- /dev/null +++ b/src/main/java/com/rits/cloning/FastClonerListOf12.java @@ -0,0 +1,20 @@ +package com.rits.cloning; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class FastClonerListOf12 implements IFastCloner { + @SuppressWarnings({"unchecked", "rawtypes"}) + public Object clone(final Object t, final IDeepCloner cloner, final Map clones) { + List al = (List) t; + if (al.size()==1){ + return List.of(al.get(0)); + }else if (al.size()==2){ + return List.of(al.get(0),al.get(1)); + }else { + return new ArrayList<>(); + } + } + +} diff --git a/src/main/java/com/rits/cloning/FastClonerSetOf12.java b/src/main/java/com/rits/cloning/FastClonerSetOf12.java new file mode 100644 index 0000000..2e024df --- /dev/null +++ b/src/main/java/com/rits/cloning/FastClonerSetOf12.java @@ -0,0 +1,18 @@ +package com.rits.cloning; + +import java.util.*; + +public class FastClonerSetOf12 implements IFastCloner{ + @SuppressWarnings({"unchecked", "rawtypes"}) + public Object clone(final Object t, final IDeepCloner cloner, final Map clones) { + Set set=(Set) t; + Object[] a=set.toArray(); + if (set.size()==1){ + return Set.of(a[0]); + }else if (set.size()==2){ + return Set.of(a[0],a[1]); + }else { + return new HashSet<>(); + } + } +} diff --git a/src/test/java/com/rits/tests/cloning/TestCloner.java b/src/test/java/com/rits/tests/cloning/TestCloner.java index 1880279..61c72d2 100644 --- a/src/test/java/com/rits/tests/cloning/TestCloner.java +++ b/src/test/java/com/rits/tests/cloning/TestCloner.java @@ -42,6 +42,14 @@ public class TestCloner extends TestCase { static private class MyAX { } + public void testCloneListOf12(){ + Assert.assertEquals(1, cloner.deepClone(List.of(1)).size()); + } + + public void testCloneSetOf12(){ + Assert.assertEquals(1, cloner.deepClone(Set.of(1)).size()); + } + public void testCalendarTimezone() { TimeZone timeZone = TimeZone.getTimeZone("America/Los_Angeles"); Calendar c = Calendar.getInstance(timeZone); From 11ab7d9f64cd1ef2e117ed3d7db402e3ec289c5e Mon Sep 17 00:00:00 2001 From: jia Date: Sat, 24 Jul 2021 09:07:18 +0800 Subject: [PATCH 8/9] feat:FastClonerListOf12 and FastClonerSetOf12 --- .../com/rits/cloning/FastClonerListOf12.java | 12 +++++++----- .../com/rits/cloning/FastClonerSetOf12.java | 18 ++++++++++-------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/rits/cloning/FastClonerListOf12.java b/src/main/java/com/rits/cloning/FastClonerListOf12.java index bd56a8f..2990b04 100644 --- a/src/main/java/com/rits/cloning/FastClonerListOf12.java +++ b/src/main/java/com/rits/cloning/FastClonerListOf12.java @@ -8,11 +8,13 @@ public class FastClonerListOf12 implements IFastCloner { @SuppressWarnings({"unchecked", "rawtypes"}) public Object clone(final Object t, final IDeepCloner cloner, final Map clones) { List al = (List) t; - if (al.size()==1){ - return List.of(al.get(0)); - }else if (al.size()==2){ - return List.of(al.get(0),al.get(1)); - }else { + if (al.size() == 1) { + return List.of(cloner.deepClone(al.get(0), clones)); + } else if (al.size() == 2) { + Object o1 = cloner.deepClone(al.get(0), clones); + Object o2 = cloner.deepClone(al.get(1), clones); + return List.of(o1, o2); + } else { return new ArrayList<>(); } } diff --git a/src/main/java/com/rits/cloning/FastClonerSetOf12.java b/src/main/java/com/rits/cloning/FastClonerSetOf12.java index 2e024df..d5bd0b9 100644 --- a/src/main/java/com/rits/cloning/FastClonerSetOf12.java +++ b/src/main/java/com/rits/cloning/FastClonerSetOf12.java @@ -2,16 +2,18 @@ import java.util.*; -public class FastClonerSetOf12 implements IFastCloner{ +public class FastClonerSetOf12 implements IFastCloner { @SuppressWarnings({"unchecked", "rawtypes"}) public Object clone(final Object t, final IDeepCloner cloner, final Map clones) { - Set set=(Set) t; - Object[] a=set.toArray(); - if (set.size()==1){ - return Set.of(a[0]); - }else if (set.size()==2){ - return Set.of(a[0],a[1]); - }else { + Set set = (Set) t; + Object[] a = set.toArray(); + if (set.size() == 1) { + return Set.of(cloner.deepClone(a[0], clones)); + } else if (set.size() == 2) { + Object o1 = cloner.deepClone(a[0], clones); + Object o2 = cloner.deepClone(a[1], clones); + return Set.of(o1, o2); + } else { return new HashSet<>(); } } From f6a15f69538d5dbe2d74e0ac7db934d6f71a7290 Mon Sep 17 00:00:00 2001 From: jia Date: Tue, 3 Aug 2021 14:30:16 +0800 Subject: [PATCH 9/9] add FastClonerListOf12 test case --- .../com/rits/tests/cloning/TestCloner.java | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/test/java/com/rits/tests/cloning/TestCloner.java b/src/test/java/com/rits/tests/cloning/TestCloner.java index 61c72d2..c1c7525 100644 --- a/src/test/java/com/rits/tests/cloning/TestCloner.java +++ b/src/test/java/com/rits/tests/cloning/TestCloner.java @@ -42,12 +42,22 @@ public class TestCloner extends TestCase { static private class MyAX { } - public void testCloneListOf12(){ - Assert.assertEquals(1, cloner.deepClone(List.of(1)).size()); - } - - public void testCloneSetOf12(){ - Assert.assertEquals(1, cloner.deepClone(Set.of(1)).size()); + public void testCloneListOf12() { + List list1 = List.of(1); + Assert.assertEquals(list1, cloner.deepClone(list1)); + Assert.assertEquals(1, cloner.deepClone(list1).size()); + List list2 = List.of(1, 2); + Assert.assertEquals(list2, cloner.deepClone(list2)); + Assert.assertEquals(2, cloner.deepClone(list2).size()); + } + + public void testCloneSetOf12() { + Set set1 = Set.of(1); + Assert.assertEquals(set1, cloner.deepClone(set1)); + Assert.assertEquals(1, cloner.deepClone(set1).size()); + Set set2 = Set.of(1, 2); + Assert.assertEquals(set2, cloner.deepClone(set2)); + Assert.assertEquals(2, cloner.deepClone(set2).size()); } public void testCalendarTimezone() {