1 4 package com.tc.util; 5 6 import org.apache.commons.lang.builder.EqualsBuilder; 7 import org.apache.commons.lang.builder.HashCodeBuilder; 8 9 import com.tc.test.TCTestCase; 10 11 import java.lang.reflect.Array ; 12 import java.util.ArrayList ; 13 import java.util.Collection ; 14 import java.util.Date ; 15 import java.util.HashMap ; 16 import java.util.HashSet ; 17 import java.util.Hashtable ; 18 import java.util.Iterator ; 19 import java.util.LinkedHashSet ; 20 import java.util.LinkedList ; 21 import java.util.Map ; 22 import java.util.TreeMap ; 23 import java.util.TreeSet ; 24 import java.util.Vector ; 25 26 29 public class DeepClonerTest extends TCTestCase { 30 31 public void testNull() { 32 assertNull(DeepCloner.deepClone(null)); 33 } 34 35 public void testValueTypes() { 36 Object [] valueObjects = new Object [] { new String ("foo"), new Boolean (true), new Character ('V'), 37 new Byte ((byte) -57), new Short ((short) 12345), new Integer (-234892352), new Long (4912840983148025L), 38 new Float (5.234789e+17), new Double (-2.48925023854e-138), new Date () }; 39 40 for (int i = 0; i < valueObjects.length; ++i) { 41 assertSame(valueObjects[i], DeepCloner.deepClone(valueObjects[i])); 42 } 43 } 44 45 public void testNonDeepCloneable() { 46 try { 47 DeepCloner.deepClone(new NonDeepCloneable()); 48 fail("Didn't get UOE on non-deep-cloneable"); 49 } catch (UnsupportedOperationException uoe) { 50 } 52 } 53 54 private static class NonDeepCloneable { 55 } 57 58 private static class MyObject implements DeepCloneable, Comparable { 59 private final String identity; 60 private final String equalsComparison; 61 private Object reference; 62 63 public MyObject(String identity, String equalsComparison) { 64 this.identity = identity; 65 this.equalsComparison = equalsComparison; 66 } 67 68 public MyObject(MyObject source, DeepCloner cloner) { 69 cloner.setClone(source, this); 70 this.identity = source.identity; 71 this.equalsComparison = source.equalsComparison; 72 this.reference = cloner.subClone(source.reference); 73 } 74 75 public void setReference(Object reference) { 76 this.reference = reference; 77 } 78 79 public String identity() { 80 return this.identity; 81 } 82 83 public String equalsComparison() { 84 return this.equalsComparison; 85 } 86 87 public Object reference() { 88 return this.reference; 89 } 90 91 public Object deepClone(DeepCloner cloner) { 92 return new MyObject(this, cloner); 93 } 94 95 public boolean equals(Object that) { 96 if (!(that instanceof MyObject)) return false; 97 98 MyObject myThat = (MyObject) that; 99 return new EqualsBuilder().append(this.equalsComparison, myThat.equalsComparison).isEquals(); 100 } 101 102 public int hashCode() { 103 return new HashCodeBuilder().append(this.equalsComparison).toHashCode(); 104 } 105 106 public int compareTo(Object o) { 107 return this.equalsComparison.compareTo(((MyObject) o).equalsComparison); 108 } 109 } 110 111 private static class MySubObject extends MyObject { 112 private Object subReference; 113 114 public MySubObject(String identity, String equalsComparison) { 115 super(identity, equalsComparison); 116 } 117 118 public MySubObject(MySubObject source, DeepCloner cloner) { 119 super(source, cloner); 120 this.subReference = cloner.subClone(source.subReference); 121 } 122 123 public Object subReference() { 124 return this.subReference; 125 } 126 127 public Object deepClone(DeepCloner cloner) { 128 return new MySubObject(this, cloner); 129 } 130 131 public void setSubReference(Object subReference) { 132 this.subReference = subReference; 133 } 134 } 135 136 private static class MyBrokenSubObject extends MyObject { 138 private Object subReference; 139 140 public MyBrokenSubObject(String identity, String equalsComparison) { 141 super(identity, equalsComparison); 142 } 143 144 public MyBrokenSubObject(MyObject source, DeepCloner cloner) { 145 super(source, cloner); 146 } 147 148 public void setSubReference(Object subReference) { 149 this.subReference = subReference; 150 } 151 152 public Object subReference() { 153 return this.subReference; 154 } 155 } 156 157 private static class MyBrokenSetCloneObject implements DeepCloneable { 158 private Object reference; 159 160 public MyBrokenSetCloneObject() { 161 this.reference = null; 162 } 163 164 private MyBrokenSetCloneObject(MyBrokenSetCloneObject source, DeepCloner cloner) { 165 cloner.setClone(this, source); 167 this.reference = cloner.subClone(source); 168 } 169 170 public void setReference(Object reference) { 171 this.reference = reference; 172 } 173 174 public Object reference() { 175 return this.reference; 176 } 177 178 public Object deepClone(DeepCloner cloner) { 179 return new MyBrokenSetCloneObject(this, cloner); 180 } 181 } 182 183 private static class MyNoSetCloneObject implements DeepCloneable { 184 private Object reference; 185 186 public MyNoSetCloneObject() { 187 this.reference = null; 188 } 189 190 private MyNoSetCloneObject(MyNoSetCloneObject source, DeepCloner cloner) { 191 this.reference = cloner.subClone(source); 192 } 193 194 public void setReference(Object reference) { 195 this.reference = reference; 196 } 197 198 public Object reference() { 199 return this.reference; 200 } 201 202 public Object deepClone(DeepCloner cloner) { 203 return new MyNoSetCloneObject(this, cloner); 204 } 205 } 206 207 public void testCircularReference() { 208 MyObject one = new MyObject("a", "b"); 209 MyObject two = new MyObject("c", "d"); 210 211 one.setReference(two); 212 two.setReference(one); 213 214 MyObject oneClone = (MyObject) DeepCloner.deepClone(one); 215 assertNotSame(one, oneClone); 216 assertNotSame(two, oneClone); 217 218 assertEquals(one, oneClone); 219 assertSame(one.identity(), oneClone.identity()); 220 assertSame(one.equalsComparison(), oneClone.equalsComparison()); 221 222 MyObject twoClone = (MyObject) oneClone.reference(); 223 224 assertNotSame(one, twoClone); 225 assertNotSame(two, twoClone); 226 227 assertEquals(two, twoClone); 228 assertSame(two.identity(), twoClone.identity()); 229 assertSame(two.equalsComparison(), twoClone.equalsComparison()); 230 231 assertSame(oneClone, twoClone.reference()); 232 } 233 234 public void testBrokenSetClone() { 235 MyBrokenSetCloneObject one = new MyBrokenSetCloneObject(); 236 MyBrokenSetCloneObject two = new MyBrokenSetCloneObject(); 237 238 one.setReference(two); 239 two.setReference(one); 240 241 try { 242 DeepCloner.deepClone(one); 243 fail("Didn't get TCAE on broken setClone() method."); 244 } catch (TCAssertionError tcae) { 245 } 247 } 248 249 public void testNoSetClone() { 250 MyNoSetCloneObject one = new MyNoSetCloneObject(); 251 MyNoSetCloneObject two = new MyNoSetCloneObject(); 252 253 one.setReference(two); 254 two.setReference(one); 255 256 try { 257 DeepCloner.deepClone(one); 258 fail("Didn't get TCAE on missing setClone() method."); 259 } catch (TCAssertionError tcae) { 260 } 262 } 263 264 public void testSimpleClone() { 265 MyObject obj = new MyObject("a", "b"); 266 obj.setReference(new Integer (432)); 267 268 MyObject clone = (MyObject) DeepCloner.deepClone(obj); 269 270 assertNotSame(obj, clone); 271 assertEquals(obj, clone); 272 assertSame(obj.identity(), clone.identity()); 273 assertSame(obj.equalsComparison(), clone.equalsComparison()); 274 assertSame(obj.reference(), clone.reference()); 275 } 276 277 public void testClonesReference() { 278 MyObject obj = new MyObject("a", "b"); 279 MyObject referredTo = new MyObject("c", "d"); 280 obj.setReference(referredTo); 281 referredTo.setReference(new Integer (543)); 282 283 MyObject clone = (MyObject) DeepCloner.deepClone(obj); 284 285 assertNotSame(obj, clone); 286 assertEquals(obj, clone); 287 assertSame(obj.identity(), clone.identity()); 288 assertSame(obj.equalsComparison(), clone.equalsComparison()); 289 290 MyObject referredToClone = (MyObject) clone.reference(); 291 assertSame(obj.reference(), referredTo); 292 assertNotSame(referredTo, referredToClone); 293 assertEquals(referredTo, referredToClone); 294 assertSame(referredTo.identity(), referredToClone.identity()); 295 assertSame(referredTo.equalsComparison(), referredToClone.equalsComparison()); 296 assertSame(referredTo.reference(), referredToClone.reference()); 297 } 298 299 public void testDoesNotMultiplyCloneObjects() { 300 MySubObject a = new MySubObject("a", "x"); 303 MyObject b = new MyObject("b", "x"); 304 MyObject c = new MyObject("c", "x"); 305 306 a.setReference(b); 307 a.setSubReference(c); 308 b.setReference(c); 309 310 MySubObject aClone = (MySubObject) DeepCloner.deepClone(a); 311 MyObject bClone = (MyObject) aClone.reference(); 312 MyObject cCloneThroughA = (MyObject) aClone.subReference(); 313 MyObject cCloneThroughB = (MyObject) bClone.reference(); 314 315 assertNotSame(a, aClone); 316 assertNotSame(b, bClone); 317 assertNotSame(c, cCloneThroughA); 318 assertNotSame(c, cCloneThroughB); 319 320 assertSame(cCloneThroughA, cCloneThroughB); 321 assertEquals(a, aClone); 322 assertEquals(b, bClone); 323 assertEquals(c, cCloneThroughA); 324 325 assertSame(a.identity(), aClone.identity()); 326 assertSame(a.equalsComparison(), aClone.equalsComparison()); 327 assertSame(b.identity(), bClone.identity()); 328 assertSame(b.equalsComparison(), bClone.equalsComparison()); 329 assertSame(c.identity(), cCloneThroughA.identity()); 330 assertSame(c.equalsComparison(), cCloneThroughA.equalsComparison()); 331 } 332 333 public void testBrokenDeepClone() { 334 try { 335 DeepCloner.deepClone(new MyBrokenSubObject("a", "b")); 336 fail("Didn't get TCAE on broken deepClone() method"); 337 } catch (TCAssertionError tcae) { 338 } 340 } 341 342 public void testCollections() throws Exception { 343 Collection [] collections = new Collection [] { new LinkedList (), new ArrayList (), new HashSet (), 344 new LinkedHashSet (), new Vector () }; 345 346 for (int i = 0; i < collections.length; ++i) { 347 checkCollection(collections[i], false); 348 } 349 350 checkCollection(new TreeSet (), true); 351 } 352 353 public void testMaps() throws Exception { 354 checkMap(new HashMap (), false); 355 checkMap(new TreeMap (), true); 356 checkMap(new Hashtable (), false); 357 } 358 359 public void testArrays() throws Exception { 360 checkPrimitiveArray(new boolean[] { true, false, false, true, false }, false); 363 checkPrimitiveArray(new char[] { 'a', 'x', 'Q' }, true); 364 checkPrimitiveArray(new byte[] { (byte) 43, (byte) -24, (byte) 14 }, true); 365 checkPrimitiveArray(new short[] { (short) 4382, (short) -4257, (short) 1442 }, true); 366 checkPrimitiveArray(new int[] { 432945, -248925, 48932525 }, true); 367 checkPrimitiveArray(new long[] { 4832908402L, -2384908209348092L, 896085049582L }, true); 368 checkPrimitiveArray(new float[] { 4.24983e+12f, -4.2438925e-14f, 1.89384205e+3f }, true); 369 checkPrimitiveArray(new double[] { 1.890810432480e+173, 2.489032842e-132, 8.32849729523e+200 }, true); 370 } 371 372 public void testObjectArray() throws Exception { 373 MySubObject a = new MySubObject("a", "a1"); 374 MyObject b = new MyObject("b", "b1"); 375 MyObject c = new MyObject("c", "c1"); 376 MyObject d = new MyObject("d", "d1"); 377 378 a.setReference(b); 379 a.setSubReference(c); 380 381 Integer integer = new Integer (12345); 382 String string = new String ("foo"); 383 384 LinkedList collection = new LinkedList (); 385 collection.add(a); 386 collection.add(d); 387 collection.add(integer); 388 389 Object [] original = new Object [] { a, collection, string }; 390 Object [] cloned = (Object []) DeepCloner.deepClone(original); 391 392 assertEquals(original.length, cloned.length); 393 394 MySubObject aCloneThroughArray = (MySubObject) cloned[0]; 395 MyObject bClone = (MyObject) aCloneThroughArray.reference(); 396 MyObject cClone = (MyObject) aCloneThroughArray.subReference(); 397 LinkedList collectionClone = (LinkedList ) cloned[1]; 398 String stringClone = (String ) cloned[2]; 399 MySubObject aCloneThroughCollection = (MySubObject) collectionClone.get(0); 400 MyObject dClone = (MyObject) collectionClone.get(1); 401 Integer integerClone = (Integer ) collectionClone.get(2); 402 403 assertNotSame(a, aCloneThroughArray); 404 assertSame(a.identity(), aCloneThroughArray.identity()); 405 assertSame(a.equalsComparison(), aCloneThroughArray.equalsComparison()); 406 407 assertNotSame(b, bClone); 408 assertSame(b.identity(), bClone.identity()); 409 assertSame(b.equalsComparison(), bClone.equalsComparison()); 410 411 assertNotSame(c, cClone); 412 assertSame(c.identity(), cClone.identity()); 413 assertSame(c.equalsComparison(), cClone.equalsComparison()); 414 415 assertNotSame(collection, collectionClone); 416 assertEquals(collection.size(), collectionClone.size()); 417 418 assertSame(aCloneThroughArray, aCloneThroughCollection); 419 420 assertNotSame(d, dClone); 421 assertSame(d.identity(), dClone.identity()); 422 assertSame(d.equalsComparison(), dClone.equalsComparison()); 423 424 assertSame(string, stringClone); 425 assertSame(integer, integerClone); 426 } 427 428 private void checkPrimitiveArray(Object array, boolean differentIdentityCheckRequired) { 429 Object clone = DeepCloner.deepClone(array); 430 431 assertNotSame(array, clone); 432 assertEquals(Array.getLength(array), Array.getLength(clone)); 433 434 for (int i = 0; i < Array.getLength(array); ++i) { 435 Object originalValue = Array.get(array, i); 436 Object clonedValue = Array.get(clone, i); 437 438 assertEquals(originalValue, clonedValue); 439 if (differentIdentityCheckRequired) { 440 assertNotSame(originalValue, clonedValue); 441 } 442 } 443 } 444 445 private void checkMap(Map map, boolean requiresOrder) { 446 MyObject aKey = new MyObject("k", "k1"); 447 MyObject aKeyRef = new MyObject("ak", "ak1"); 448 aKey.setReference(aKeyRef); 449 450 MyObject bKey = new MyObject("b", "b1"); 451 bKey.setReference(aKeyRef); 452 453 MyObject cKey = new MyObject("c", "c1"); 454 455 MySubObject a = new MySubObject("a", "b"); 456 MyObject ref = new MyObject("ref", "ref1"); 457 MyObject subRef = new MyObject("subRef", "subRef1"); 458 Integer integer = new Integer (42); 459 String string = new String ("foo"); 460 461 a.setReference(ref); 462 a.setSubReference(subRef); 463 464 LinkedList list = new LinkedList (); 465 list.add(ref); 466 list.add(string); 467 468 map.put(aKey, a); 469 if (!requiresOrder) { 470 map.put(bKey, list); 471 map.put(cKey, integer); 472 } 473 474 Map cloned = (Map ) DeepCloner.deepClone(map); 475 476 assertNotSame(map, cloned); 477 478 Iterator iter = cloned.entrySet().iterator(); 479 MyObject aCloneRef = null; 480 boolean haveA = false, haveB = false, haveC = false; 481 482 while (iter.hasNext()) { 483 Map.Entry entry = (Map.Entry ) iter.next(); 484 MyObject key = (MyObject) entry.getKey(); 485 Object value = entry.getValue(); 486 487 if (key.equals(aKey)) { 488 assertNotSame(aKey, key); 489 assertSame(aKey.identity(), key.identity()); 490 assertSame(aKey.equalsComparison(), key.equalsComparison()); 491 492 MyObject keyRef = (MyObject) key.reference(); 493 assertNotSame(aKeyRef, keyRef); 494 assertSame(aKeyRef.identity(), keyRef.identity()); 495 assertSame(aKeyRef.equalsComparison(), keyRef.equalsComparison()); 496 497 MySubObject aClone = (MySubObject) value; 498 MyObject thisACloneRef = (MyObject) aClone.reference(); 499 if (aCloneRef != null) assertSame(aCloneRef, thisACloneRef); 500 else aCloneRef = thisACloneRef; 501 MyObject aCloneSubRef = (MyObject) aClone.subReference(); 502 503 assertNotSame(a, aClone); 504 assertSame(a.identity(), aClone.identity()); 505 assertSame(a.equalsComparison(), aClone.equalsComparison()); 506 507 assertNotSame(ref, aCloneRef); 508 assertSame(ref.identity(), aCloneRef.identity()); 509 assertSame(ref.equalsComparison(), aCloneRef.equalsComparison()); 510 assertSame(ref.reference(), aCloneRef.reference()); 511 512 assertNotSame(subRef, aCloneSubRef); 513 assertSame(subRef.identity(), aCloneSubRef.identity()); 514 assertSame(subRef.equalsComparison(), aCloneSubRef.equalsComparison()); 515 assertSame(subRef.reference(), aCloneSubRef.reference()); 516 517 haveA = true; 518 } else if (key.equals(bKey)) { 519 assertNotSame(bKey, key); 520 assertSame(bKey.identity(), key.identity()); 521 assertSame(bKey.equalsComparison(), key.equalsComparison()); 522 523 LinkedList listClone = (LinkedList ) value; 524 MyObject thisACloneRef = (MyObject) listClone.get(0); 525 if (aCloneRef != null) assertSame(aCloneRef, thisACloneRef); 526 else aCloneRef = thisACloneRef; 527 assertSame(string, list.get(1)); 528 529 haveB = true; 530 } else if (key.equals(cKey)) { 531 assertNotSame(cKey, key); 532 assertSame(cKey.identity(), key.identity()); 533 assertSame(cKey.equalsComparison(), key.equalsComparison()); 534 535 assertSame(integer, value); 536 537 haveC = true; 538 } else { 539 fail("Unknown key: " + key); 540 } 541 } 542 543 assertTrue(haveA); 544 assertEquals(!requiresOrder, haveB); 545 assertEquals(!requiresOrder, haveC); 546 } 547 548 private void checkCollection(Collection collection, boolean requiresOrder) { 549 MySubObject a = new MySubObject("a", "b"); 550 MyObject ref = new MyObject("ref", "ref1"); 551 MyObject subRef = new MyObject("subRef", "subRef1"); 552 Integer integer = new Integer (42); 553 String string = new String ("foo"); 554 555 a.setReference(ref); 556 a.setSubReference(subRef); 557 558 LinkedList list = new LinkedList (); 559 list.add(ref); 560 list.add(string); 561 562 collection.add(a); 563 if (!requiresOrder) { 564 collection.add(list); 567 collection.add(integer); 568 } 569 570 Collection cloned = (Collection ) DeepCloner.deepClone(collection); 571 572 assertNotSame(collection, cloned); 573 574 Iterator clonedIter = cloned.iterator(); 575 MySubObject clonedA = null; 576 LinkedList clonedList = null; 577 Integer clonedInteger = null; 578 579 while (clonedIter.hasNext()) { 580 Object next = clonedIter.next(); 581 if (next instanceof MySubObject) { 582 assertNull(clonedA); 583 clonedA = (MySubObject) next; 584 } else if (next instanceof LinkedList ) { 585 assertNull(clonedList); 586 clonedList = (LinkedList ) next; 587 } else if (next instanceof Integer ) { 588 assertNull(clonedInteger); 589 clonedInteger = (Integer ) next; 590 } else { 591 fail("Unknown object in collection: " + next); 592 } 593 } 594 595 assertNotSame(a, clonedA); 596 if (!requiresOrder) { 597 assertNotSame(list, clonedList); 598 assertSame(integer, clonedInteger); 599 } 600 601 MyObject clonedRef = (MyObject) clonedA.reference(); 602 MyObject clonedSubRef = (MyObject) clonedA.subReference(); 603 604 assertNotSame(ref, clonedRef); 605 assertSame(ref.identity(), clonedRef.identity()); 606 assertSame(ref.equalsComparison(), clonedRef.equalsComparison()); 607 assertNull(ref.reference()); 608 609 assertNotSame(subRef, clonedSubRef); 610 assertSame(subRef.identity(), clonedSubRef.identity()); 611 assertSame(subRef.equalsComparison(), clonedSubRef.equalsComparison()); 612 assertNull(subRef.reference()); 613 614 if (!requiresOrder) { 615 assertSame(clonedRef, clonedList.get(0)); 616 assertSame(string, clonedList.get(1)); 617 assertEquals(2, clonedList.size()); 618 } 619 } 620 621 } 622 | Popular Tags |