1   /*
2    * Copyright 2006-2010 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package net.sourceforge.domian.util;
17  
18  
19  import java.io.File;
20  import static java.lang.Boolean.TRUE;
21  import java.lang.reflect.Field;
22  import java.lang.reflect.Method;
23  import java.lang.reflect.Type;
24  import java.util.Collection;
25  import java.util.Date;
26  import java.util.HashSet;
27  
28  import org.apache.commons.lang.builder.EqualsBuilder;
29  import org.apache.commons.lang.math.RandomUtils;
30  
31  import net.sourceforge.domian.test.domain.Customer;
32  import static net.sourceforge.domian.test.domain.Customer.Gender;
33  import net.sourceforge.domian.test.domain.Order;
34  import net.sourceforge.domian.test.domain.OrderLine;
35  import static net.sourceforge.domian.test.domain.Testdata.maleCustomer;
36  import static net.sourceforge.domian.test.domain.Testdata.maleCustomerOrder1;
37  import static net.sourceforge.domian.test.domain.Testdata.twentyYearsAgo;
38  import static net.sourceforge.domian.test.domain.Testdata.twoDaysAgo;
39  import static net.sourceforge.domian.test.domain.Testdata.yesterday;
40  import net.sourceforge.domian.test.domain.VipCustomer;
41  import static net.sourceforge.domian.util.DateUtils.getTime;
42  
43  import junit.framework.TestCase;
44  
45  
46  public class ReflectionUtilsTest extends TestCase {
47  
48      public void testCanCastFrom_To() {
49          assertFalse(ReflectionUtils.canCastFrom_To(null, String.class));
50          assertFalse(ReflectionUtils.canCastFrom_To(String.class, null));
51  
52          assertTrue(ReflectionUtils.canCastFrom_To(String.class, String.class));
53          assertTrue(ReflectionUtils.canCastFrom_To(Long.class, Long.class));
54  
55          assertFalse(ReflectionUtils.canCastFrom_To(Date.class, Long.class));
56  
57          assertTrue(ReflectionUtils.canCastFrom_To(long.class, Long.class));
58          assertTrue(ReflectionUtils.canCastFrom_To(long.class, Number.class));
59          assertTrue(ReflectionUtils.canCastFrom_To(int.class, Integer.class));
60          assertTrue(ReflectionUtils.canCastFrom_To(int.class, Number.class));
61          assertTrue(ReflectionUtils.canCastFrom_To(double.class, Double.class));
62          assertTrue(ReflectionUtils.canCastFrom_To(double.class, Number.class));
63          assertTrue(ReflectionUtils.canCastFrom_To(float.class, Float.class));
64          assertTrue(ReflectionUtils.canCastFrom_To(float.class, Number.class));
65          assertTrue(ReflectionUtils.canCastFrom_To(short.class, Short.class));
66          assertTrue(ReflectionUtils.canCastFrom_To(short.class, Number.class));
67  
68          assertFalse(ReflectionUtils.canCastFrom_To(Number.class, Long.class));
69          assertTrue(ReflectionUtils.canCastFrom_To(Long.class, Number.class));
70  
71          assertFalse(ReflectionUtils.canCastFrom_To(Integer.class, Long.class));
72          assertFalse(ReflectionUtils.canCastFrom_To(int.class, long.class));
73  
74          assertFalse(ReflectionUtils.canCastFrom_To(Collection.class, HashSet.class));
75          assertTrue(ReflectionUtils.canCastFrom_To(HashSet.class, Collection.class));
76  
77          assertFalse(ReflectionUtils.canCastFrom_To((Type) Collection.class, HashSet.class));
78          assertTrue(ReflectionUtils.canCastFrom_To(HashSet.class, (Type) Collection.class));
79      }
80  
81  
82      public void testCanCastAtLeastOneWay() {
83          assertFalse(ReflectionUtils.canCastAtLeastOneWay(null, String.class));
84          assertFalse(ReflectionUtils.canCastAtLeastOneWay(String.class, null));
85  
86          assertTrue(ReflectionUtils.canCastAtLeastOneWay(String.class, String.class));
87          assertTrue(ReflectionUtils.canCastAtLeastOneWay(Long.class, Long.class));
88  
89          assertFalse(ReflectionUtils.canCastAtLeastOneWay(Date.class, Long.class));
90  
91          assertTrue(ReflectionUtils.canCastAtLeastOneWay(Number.class, Long.class));
92          assertTrue(ReflectionUtils.canCastAtLeastOneWay(Long.class, Number.class));
93  
94          assertTrue(ReflectionUtils.canCastAtLeastOneWay(Collection.class, HashSet.class));
95          assertTrue(ReflectionUtils.canCastAtLeastOneWay(HashSet.class, Collection.class));
96  
97          assertTrue(ReflectionUtils.canCastAtLeastOneWay((Type) Collection.class, HashSet.class));
98          assertTrue(ReflectionUtils.canCastAtLeastOneWay(HashSet.class, (Type) Collection.class));
99      }
100 
101 
102     public void testGetFieldByName_NullFieldName() {
103         try {
104             ReflectionUtils.getFieldByName(null, Order.class);
105             fail("Should have thrown exception");
106 
107         } catch (IllegalArgumentException e) {
108             String expectedMessage = "Field name parameter cannot be null";
109             assertEquals(expectedMessage, e.getMessage());
110         }
111     }
112 
113 
114     public void testGetFieldByName_NullType() {
115         try {
116             ReflectionUtils.getFieldByName("orderId", null);
117             fail("Should have thrown exception");
118 
119         } catch (IllegalArgumentException e) {
120             String expectedMessage = "Type parameter cannot be null";
121             assertEquals(expectedMessage, e.getMessage());
122         }
123     }
124 
125 
126     public void testGetFieldByName_NonExisting() {
127         assertNull(ReflectionUtils.getFieldByName("nonExistingField", Order.class));
128     }
129 
130 
131     public void testGetFieldByName() {
132         Field orderIdField = ReflectionUtils.getFieldByName("orderId", Order.class);
133         assertEquals("orderId", orderIdField.getName());
134         assertEquals(Long.class, orderIdField.getGenericType());
135     }
136 
137 
138     public void testGetFieldByName_ShouldAcceptFieldsInSuperclasses() {
139         Field vipCustomerSinceField = ReflectionUtils.getFieldByName("vipCustomerSince", VipCustomer.class);
140         assertEquals("vipCustomerSince", vipCustomerSinceField.getName());
141         assertEquals(Date.class, vipCustomerSinceField.getGenericType());
142 
143         Field nameField = ReflectionUtils.getFieldByName("name", VipCustomer.class);
144         assertEquals("name", nameField.getName());
145         assertEquals(String.class, nameField.getGenericType());
146 
147         Field customerIdField = ReflectionUtils.getFieldByName("customerId", VipCustomer.class);
148         assertEquals("customerId", customerIdField.getName());
149         assertEquals(Customer.class, customerIdField.getDeclaringClass());
150         assertEquals(Long.class, customerIdField.getGenericType());
151         assertEquals(Long.class, customerIdField.getType());
152     }
153 
154 
155     public void testGetMethodByName_NullMethodName() {
156         try {
157             ReflectionUtils.getMethodByName(null, OrderLine.class);
158             fail("Should have thrown exception");
159 
160         } catch (IllegalArgumentException e) {
161             String expectedMessage = "Method name parameter cannot be null";
162             assertEquals(expectedMessage, e.getMessage());
163         }
164     }
165 
166 
167     public void testGetMethodByName_NullType() {
168         try {
169             ReflectionUtils.getMethodByName("paymentReceived", null);
170             fail("Should have thrown exception");
171 
172         } catch (IllegalArgumentException e) {
173             String expectedMessage = "Type parameter cannot be null";
174             assertEquals(expectedMessage, e.getMessage());
175         }
176     }
177 
178 
179     public void testGetMethodByName_NonExisting() {
180         assertNull(ReflectionUtils.getMethodByName("nonExistingMethod", OrderLine.class));
181     }
182 
183 
184     public void testGetMethodByName() {
185         Method method = ReflectionUtils.getMethodByName("pending", OrderLine.class);
186         assertEquals("pending", method.getName());
187         assertEquals(Boolean.class, method.getReturnType());
188 
189         method = ReflectionUtils.getMethodByName("isPending", OrderLine.class);
190         assertEquals("isPending", method.getName());
191         assertEquals(boolean.class, method.getReturnType());
192 
193         method = ReflectionUtils.getMethodByName("cancelled", new Class[]{boolean.class}, OrderLine.class);
194         assertEquals("cancelled", method.getName());
195         assertEquals(OrderLine.class, method.getReturnType());
196     }
197 
198 
199     public void testGetMethodByName_ShouldAcceptMethodsInSuperclasses() {
200         Method method = ReflectionUtils.getMethodByName("addOrder", new Class[]{Order.class}, VipCustomer.class);
201         assertEquals("addOrder", method.getName());
202         assertEquals(void.class, method.getReturnType());
203     }
204 
205 
206     public void testInvokeMethod() {
207         Customer customer = new Customer(1234L, twentyYearsAgo).gender(Gender.MALE).name("John");
208         assertEquals(customer.getName(), ReflectionUtils.invokeMethod(customer, "getName", null));
209         assertNull(ReflectionUtils.invokeMethod(customer, "setName", null));
210         assertNull(ReflectionUtils.invokeMethod(customer, "setName", new Object[]{}));
211         assertNull(ReflectionUtils.invokeMethod(customer, "setName", new Object[]{"Peter"}));
212         assertEquals("Peter", ReflectionUtils.invokeMethod(customer, "getName"));
213     }
214 
215 
216     public void testCloneOrDeepCopyIfNotImmutable() {
217         /* maleCustomerOrder1 = new Order(1021L, yesterday, maleCustomer, createOrderlineListWith(new OrderLine[]{new OrderLine(10211L)})); */
218         /* maleCustomer = new Customer(102L, yesterday).name("Eirik").gender(Customer.Gender.MALE).birthDate(getTime(1970, 10, 25)).vip(Boolean.TRUE); */
219         Order order = maleCustomerOrder1;
220         /* Should be cloned because it does not extend AbstractUUIDEntity (if object copying is activated that is) */
221         Order clonedOrder = ReflectionUtils.cloneOrDeepCopyIfNotImmutable(order);
222         if (ReflectionUtils.DO_COPY_OBJECTS) {
223             assertNotSame(order, clonedOrder);
224             assertEquals(order, clonedOrder);
225 
226             assertNotSame(yesterday, clonedOrder.getOrderDate());
227             assertEquals(yesterday, clonedOrder.getOrderDate());
228 
229             if (ReflectionUtils.DO_COPY_ENTITIES) {
230                 assertNotSame(maleCustomer, clonedOrder.getCustomer());
231                 assertEquals(maleCustomer, clonedOrder.getCustomer());
232                 assertNotSame(maleCustomer.getMembershipDate(), clonedOrder.getCustomer().getMembershipDate());
233                 assertEquals(maleCustomer.getMembershipDate(), clonedOrder.getCustomer().getMembershipDate());
234                 assertNotSame(maleCustomer.getBirthDate(), clonedOrder.getCustomer().getBirthDate());
235                 assertEquals(maleCustomer.getBirthDate(), clonedOrder.getCustomer().getBirthDate());
236             } else {
237                 assertSame(maleCustomer, clonedOrder.getCustomer());
238                 assertSame(maleCustomer.getMembershipDate(), clonedOrder.getCustomer().getMembershipDate());
239                 assertSame(maleCustomer.getBirthDate(), clonedOrder.getCustomer().getBirthDate());
240             }
241             assertSame(maleCustomer.getGender(), clonedOrder.getCustomer().getGender()); // Enum types are immutable and should be the same object
242             assertSame(maleCustomer.getForeign(), clonedOrder.getCustomer().getForeign()); // Boolean types are immutable and should be the same object
243             assertEquals(1, clonedOrder.getOrderLines().size());
244             assertNotSame(order.getOrderLines().get(0), clonedOrder.getOrderLines().get(0));
245             assertEquals(order.getOrderLines().get(0), clonedOrder.getOrderLines().get(0));
246             assertEquals(10211, clonedOrder.getOrderLines().get(0).getOrderLineId());
247             assertSame(Boolean.FALSE, clonedOrder.getOrderLines().get(0).isCancelled()); // Boolean types are immutable and should be the same object
248             assertSame(false, clonedOrder.getOrderLines().get(0).isPaymentReceived()); // Boolean types are immutable and should be the same object
249 
250         } else {
251             assertSame(order, clonedOrder);
252             assertSame(maleCustomer, clonedOrder.getCustomer());
253             assertSame(yesterday, clonedOrder.getOrderDate());
254 
255             assertSame(maleCustomer, clonedOrder.getCustomer());
256             assertSame(maleCustomer.getMembershipDate(), clonedOrder.getCustomer().getMembershipDate());
257             assertSame(maleCustomer.getBirthDate(), clonedOrder.getCustomer().getBirthDate());
258             assertSame(maleCustomer.getGender(), clonedOrder.getCustomer().getGender()); // Enum types are immutable and should be the same object
259             assertSame(maleCustomer.getForeign(), clonedOrder.getCustomer().getForeign()); // Boolean types are immutable and should be the same object
260             assertEquals(1, clonedOrder.getOrderLines().size());
261             assertSame(order.getOrderLines().get(0), clonedOrder.getOrderLines().get(0));
262             assertSame(Boolean.FALSE, clonedOrder.getOrderLines().get(0).isCancelled());
263             assertSame(false, clonedOrder.getOrderLines().get(0).isPaymentReceived());
264         }
265     }
266 
267 
268     public void testCloneOrDeepCopyIfNotImmutable_MapFields() {
269         /* maleCustomer = new Customer(102L, yesterday).name("Eirik").gender(Customer.Gender.MALE).birthDate(getTime(1970, 10, 25)).vip(Boolean.TRUE); */
270         Order order = new Order(8080L);
271         order.setCustomer(maleCustomer);
272         order.setOrderDate(twoDaysAgo);
273         OrderLine orderLine1 = new OrderLine(80801L);
274         OrderLine orderLine2 = new OrderLine(80802L);
275         OrderLine orderLine3 = new OrderLine(80803L);
276         order.addOrderLine(orderLine1);
277         order.addOrderLine(orderLine2);
278         order.addOrderLine(orderLine3);
279         order.addSelectedOrderLine(orderLine2);
280 
281         /* Should be cloned because it does not extends AbstractUUIDEntity (if object copying is activated) */
282         Order clonedOrder = ReflectionUtils.cloneOrDeepCopyIfNotImmutable(order);
283         if (ReflectionUtils.DO_COPY_OBJECTS) {
284             assertNotSame(order, clonedOrder);
285             assertEquals(order, clonedOrder);
286             assertSame(order.getOrderId(), clonedOrder.getOrderId()); // Number types are immutable and should be the same object
287             if (ReflectionUtils.DO_COPY_ENTITIES) {
288                 assertNotSame(maleCustomer, clonedOrder.getCustomer());
289                 assertEquals(maleCustomer, clonedOrder.getCustomer());
290                 assertNotSame(maleCustomer.getMembershipDate(), clonedOrder.getCustomer().getMembershipDate());
291                 assertEquals(maleCustomer.getMembershipDate(), clonedOrder.getCustomer().getMembershipDate());
292                 assertNotSame(maleCustomer.getBirthDate(), clonedOrder.getCustomer().getBirthDate());
293                 assertEquals(maleCustomer.getBirthDate(), clonedOrder.getCustomer().getBirthDate());
294             } else {
295                 assertSame(maleCustomer, clonedOrder.getCustomer());
296                 assertSame(maleCustomer.getMembershipDate(), clonedOrder.getCustomer().getMembershipDate());
297                 assertSame(maleCustomer.getBirthDate(), clonedOrder.getCustomer().getBirthDate());
298             }
299             assertEquals(order.getOrderDate(), clonedOrder.getOrderDate());
300             assertNotSame(order.getOrderLines(), clonedOrder.getOrderLines());
301             assertEquals(order.getOrderLines(), clonedOrder.getOrderLines());
302             assertNotSame(order.getOrderLines().get(2), clonedOrder.getOrderLines().get(2));
303             assertEquals(order.getOrderLines().get(2), clonedOrder.getOrderLines().get(2));
304             assertNotSame(order.getSelectedOrderLines(), clonedOrder.getSelectedOrderLines());
305             assertEquals(order.getSelectedOrderLines(), clonedOrder.getSelectedOrderLines());
306             assertNull(order.getSelectedOrderLines().get(orderLine1.getOrderLineId()));
307             assertNull(clonedOrder.getSelectedOrderLines().get(orderLine1.getOrderLineId()));
308             assertSame(orderLine2, order.getSelectedOrderLines().get(orderLine2.getOrderLineId()));
309             assertNotSame(orderLine2, clonedOrder.getSelectedOrderLines().get(orderLine2.getOrderLineId()));
310             assertEquals(orderLine2, clonedOrder.getSelectedOrderLines().get(orderLine2.getOrderLineId()));
311             assertNotSame(order.getSelectedOrderLines().get(orderLine2.getOrderLineId()), clonedOrder.getSelectedOrderLines().get(orderLine2.getOrderLineId()));
312             assertEquals(order.getSelectedOrderLines().get(orderLine2.getOrderLineId()), clonedOrder.getSelectedOrderLines().get(orderLine2.getOrderLineId()));
313 
314         } else {
315             assertSame(order, clonedOrder);
316             assertSame(maleCustomer, clonedOrder.getCustomer());
317             assertSame(twoDaysAgo, clonedOrder.getOrderDate());
318 
319             assertSame(maleCustomer, clonedOrder.getCustomer());
320             assertSame(maleCustomer.getMembershipDate(), clonedOrder.getCustomer().getMembershipDate());
321             assertSame(maleCustomer.getBirthDate(), clonedOrder.getCustomer().getBirthDate());
322             assertSame(maleCustomer.getGender(), clonedOrder.getCustomer().getGender()); // Enum types are immutable and should be the same object
323             assertSame(maleCustomer.getForeign(), clonedOrder.getCustomer().getForeign()); // Boolean types are immutable and should be the same object
324             assertEquals(3, clonedOrder.getOrderLines().size());
325             assertSame(order.getOrderLines().get(0), clonedOrder.getOrderLines().get(0));
326             assertSame(Boolean.FALSE, clonedOrder.getOrderLines().get(0).isCancelled()); // Boolean types are immutable and should be the same object
327             assertSame(false, clonedOrder.getOrderLines().get(0).isPaymentReceived()); // Boolean types are immutable and should be the same object
328         }
329 
330         /* Should be cloned because it does not extends AbstractUUIDEntity (if object copying is activated) */
331         if (ReflectionUtils.DO_COPY_OBJECTS) {
332             assertNotSame(order, clonedOrder);
333             assertEquals(order, clonedOrder);
334 
335             assertNotSame(twoDaysAgo, clonedOrder.getOrderDate());
336             assertEquals(twoDaysAgo, clonedOrder.getOrderDate());
337 
338             if (ReflectionUtils.DO_COPY_ENTITIES) {
339                 assertNotSame(maleCustomer, clonedOrder.getCustomer());
340                 assertEquals(maleCustomer, clonedOrder.getCustomer());
341                 assertNotSame(maleCustomer.getMembershipDate(), clonedOrder.getCustomer().getMembershipDate());
342                 assertEquals(maleCustomer.getMembershipDate(), clonedOrder.getCustomer().getMembershipDate());
343                 assertNotSame(maleCustomer.getBirthDate(), clonedOrder.getCustomer().getBirthDate());
344                 assertEquals(maleCustomer.getBirthDate(), clonedOrder.getCustomer().getBirthDate());
345             } else {
346                 assertSame(maleCustomer, clonedOrder.getCustomer());
347                 assertSame(maleCustomer.getMembershipDate(), clonedOrder.getCustomer().getMembershipDate());
348                 assertSame(maleCustomer.getBirthDate(), clonedOrder.getCustomer().getBirthDate());
349             }
350             assertSame(maleCustomer.getGender(), clonedOrder.getCustomer().getGender()); // Enum types are immutable and should be the same object
351             assertSame(maleCustomer.getForeign(), clonedOrder.getCustomer().getForeign()); // Boolean types are immutable and should be the same object
352             assertEquals(3, clonedOrder.getOrderLines().size());
353             assertNotSame(order.getOrderLines().get(0), clonedOrder.getOrderLines().get(0));
354             assertEquals(order.getOrderLines().get(0), clonedOrder.getOrderLines().get(0));
355             assertEquals(80801L, clonedOrder.getOrderLines().get(0).getOrderLineId());
356             assertSame(Boolean.FALSE, clonedOrder.getOrderLines().get(0).isCancelled()); // Boolean types are immutable and should be the same object
357             assertSame(false, clonedOrder.getOrderLines().get(0).isPaymentReceived()); // Boolean types are immutable and should be the same object
358         }
359     }
360 
361 
362     public void testCloneOrDeepCopyIfNotImmutable_RecursiveReferences() {
363         Order order = new Order(8080L);
364         order.setOrderDate(twoDaysAgo);
365         OrderLine orderLine1 = new OrderLine(80801L);
366         OrderLine orderLine2 = new OrderLine(80802L);
367         OrderLine orderLine3 = new OrderLine(80803L);
368         order.addOrderLine(orderLine1);
369         order.addOrderLine(orderLine2);
370         order.addOrderLine(orderLine3);
371         order.addSelectedOrderLine(orderLine2);
372 
373         Customer customer = new Customer(102L, yesterday).name("Eirik").gender(Gender.MALE).birthDate(getTime(1970, 10, 25)).foreign(TRUE);
374         customer.addOrder(order);
375 
376         /* Should be cloned because it does not extends AbstractUUIDEntity (if object copying is activated) */
377         Order clonedOrder = ReflectionUtils.cloneOrDeepCopyIfNotImmutable(order);
378         if (ReflectionUtils.DO_COPY_OBJECTS) {
379             assertNotSame(order, clonedOrder);
380             assertEquals(order, clonedOrder);
381 
382             // Not cloned because it extends AbstractUUIDEntity, with its immutable hashCode/equals methods (if entity copying is deactivated)
383             Customer implicitlyClonedCustomer = clonedOrder.getCustomer();
384             if (ReflectionUtils.DO_COPY_ENTITIES) {
385                 assertNotSame(implicitlyClonedCustomer, customer);
386                 assertEquals(implicitlyClonedCustomer, customer);
387             } else {
388                 assertSame(implicitlyClonedCustomer, customer);
389             }
390             assertSame(customer, order.getCustomer());
391             assertSame(order, customer.getOrders().get(0));
392             if (ReflectionUtils.DO_COPY_ENTITIES) {
393                 assertNotSame(implicitlyClonedCustomer, order.getCustomer());
394                 assertEquals(implicitlyClonedCustomer, order.getCustomer());
395                 assertSame(implicitlyClonedCustomer, clonedOrder.getCustomer());
396                 assertSame(clonedOrder, implicitlyClonedCustomer.getOrders().get(0));
397             } else {
398                 assertSame(customer, clonedOrder.getCustomer());
399                 assertSame(implicitlyClonedCustomer, order.getCustomer());
400                 assertSame(implicitlyClonedCustomer, clonedOrder.getCustomer());
401                 assertNotSame(clonedOrder, implicitlyClonedCustomer.getOrders().get(0));
402                 assertEquals(clonedOrder, implicitlyClonedCustomer.getOrders().get(0));
403             }
404 
405         } else {
406             assertSame(order, clonedOrder);
407             assertSame(customer, clonedOrder.getCustomer());
408         }
409     }
410 
411 
412     public void testCloneOrDeepCopyIfNotImmutable_SameTypeReflecsiveReference() {
413         ClassWithFieldOfSameType obj = new ClassWithFieldOfSameType();
414         ClassWithFieldOfSameType clonedObj = ReflectionUtils.cloneOrDeepCopyIfNotImmutable(obj);
415         if (ReflectionUtils.DO_COPY_OBJECTS) {
416             assertNotSame(obj, clonedObj);
417             assertEquals(obj, clonedObj);
418 
419             obj.sameTypeRef = obj;
420             ClassWithFieldOfSameType clonedObj2 = ReflectionUtils.cloneOrDeepCopyIfNotImmutable(obj);
421             assertNotSame(obj, clonedObj2);
422             assertEquals(obj, clonedObj2);
423 
424             assertSame(obj, obj);
425             assertSame(obj, obj.sameTypeRef);
426 
427             assertSame(clonedObj2, clonedObj2);
428             assertSame(clonedObj2, clonedObj2.sameTypeRef);
429 
430         } else {
431             assertSame(obj, clonedObj);
432             obj.sameTypeRef = obj;
433             ClassWithFieldOfSameType clonedObj2 = ReflectionUtils.cloneOrDeepCopyIfNotImmutable(obj);
434             assertSame(obj, clonedObj2);
435             assertSame(obj, obj.sameTypeRef);
436             assertSame(clonedObj2, clonedObj2.sameTypeRef);
437         }
438     }
439 
440 
441     public void testCloneOrDeepCopyIfNotImmutable_ArrayOfCustomers() {
442         ClassWithCustomerArray obj = new ClassWithCustomerArray();
443         ClassWithCustomerArray clonedObj = ReflectionUtils.cloneOrDeepCopyIfNotImmutable(obj);
444         if (ReflectionUtils.DO_COPY_OBJECTS) {
445             assertNotSame(obj, clonedObj);
446             assertEquals(obj, clonedObj);
447 
448             obj.customerArray[0] = maleCustomer;
449             ClassWithCustomerArray clonedObj2 = ReflectionUtils.cloneOrDeepCopyIfNotImmutable(obj);
450             assertNotSame(obj, clonedObj2);
451             assertEquals(obj, clonedObj2);
452 
453             assertSame(maleCustomer, obj.customerArray[0]);
454             if (ReflectionUtils.DO_COPY_ENTITIES) {
455                 assertNotSame(maleCustomer, clonedObj2.customerArray[0]);
456                 assertEquals(maleCustomer, clonedObj2.customerArray[0]);
457             } else {
458                 assertSame(maleCustomer, clonedObj2.customerArray[0]);
459             }
460 
461         } else {
462             assertSame(obj, clonedObj);
463             obj.customerArray[0] = maleCustomer;
464             ClassWithCustomerArray clonedObj2 = ReflectionUtils.cloneOrDeepCopyIfNotImmutable(obj);
465             assertSame(obj, clonedObj2);
466             assertSame(maleCustomer, obj.customerArray[0]);
467             assertSame(maleCustomer, clonedObj2.customerArray[0]);
468         }
469     }
470 
471 
472     public void testCloneOrDeepCopyIfNotImmutable_ArrayOfSameTypeReflecsiveReferences() {
473         ClassWithFieldArrayOfSameType obj = new ClassWithFieldArrayOfSameType();
474         ClassWithFieldArrayOfSameType clonedObj = ReflectionUtils.cloneOrDeepCopyIfNotImmutable(obj);
475         if (ReflectionUtils.DO_COPY_OBJECTS) {
476             assertNotSame(obj, clonedObj);
477             assertEquals(obj, clonedObj);
478 
479             obj.fieldArrayOfSameType[0] = obj;
480             ClassWithFieldArrayOfSameType clonedObj2 = ReflectionUtils.cloneOrDeepCopyIfNotImmutable(obj);
481             assertNotSame(obj, clonedObj2);
482             assertEquals(obj, clonedObj2);
483 
484             assertSame(obj, obj);
485             assertSame(obj, obj.fieldArrayOfSameType[0]);
486             assertSame(clonedObj2, clonedObj2);
487             assertSame(clonedObj2, clonedObj2.fieldArrayOfSameType[0]);
488 
489         } else {
490             assertSame(obj, clonedObj);
491             obj.fieldArrayOfSameType[0] = obj;
492             ClassWithFieldArrayOfSameType clonedObj2 = ReflectionUtils.cloneOrDeepCopyIfNotImmutable(obj);
493             assertSame(obj, clonedObj2);
494             assertSame(obj, obj);
495             assertSame(obj, obj.fieldArrayOfSameType[0]);
496             assertSame(clonedObj2, clonedObj2);
497             assertSame(clonedObj2, clonedObj2.fieldArrayOfSameType[0]);
498         }
499     }
500 
501 
502     public void testCloneOrDeepCopyIfNotImmutable_DoNotCopyOverride() {
503         Order order = maleCustomerOrder1;
504         Order clonedOrder = ReflectionUtils.cloneOrDeepCopyIfNotImmutable(order);
505         if (ReflectionUtils.DO_COPY_OBJECTS) {
506             assertNotSame(order, clonedOrder);
507             assertEquals(order, clonedOrder);
508 
509             ReflectionUtils.DO_COPY_OBJECTS = false;
510             clonedOrder = ReflectionUtils.cloneOrDeepCopyIfNotImmutable(order);
511             assertSame(order, clonedOrder);
512 
513             // Reset: very important!
514             ReflectionUtils.DO_COPY_OBJECTS = true;
515         }
516     }
517 
518 
519     public void testCloneOrDeepCopyIfNotImmutable_RecursiveDepthTreshold() {
520         // Default recursive treshold is 5 (not 3 as before...)
521         Level0FieldClass obj = new Level0FieldClass();
522         Level0FieldClass clonedObj = ReflectionUtils.cloneOrDeepCopyIfNotImmutable(obj);
523 
524         if (ReflectionUtils.DO_COPY_OBJECTS) {
525             // Treshold:      1                2                3                4                5                6
526             assertNotNull(obj.level1FieldClass.level2FieldClass.level3FieldClass.level4FieldClass.level5FieldClass.level6FieldClass);
527             assertNull(clonedObj.level1FieldClass.level2FieldClass.level3FieldClass.level4FieldClass.level5FieldClass.level6FieldClass);
528 
529             // Setting treshold to 0
530             ReflectionUtils.RECURSIVE_COPYING_DEPTH_TRESHOLD = 0;
531             clonedObj = ReflectionUtils.cloneOrDeepCopyIfNotImmutable(obj);
532 
533             // Treshold:     1
534             assertNotNull(obj.level1FieldClass);
535             assertNull(clonedObj.level1FieldClass);
536 
537             // Reset: very important!
538             ReflectionUtils.RECURSIVE_COPYING_DEPTH_TRESHOLD = 3;
539 
540         } else {
541             // Treshold:      1                2                3                4                5                6
542             assertNotNull(obj.level1FieldClass.level2FieldClass.level3FieldClass.level4FieldClass.level5FieldClass.level6FieldClass);
543             assertNotNull(clonedObj.level1FieldClass.level2FieldClass.level3FieldClass.level4FieldClass.level5FieldClass.level6FieldClass);
544 
545             // Setting treshold to 0
546             ReflectionUtils.RECURSIVE_COPYING_DEPTH_TRESHOLD = 0;
547             clonedObj = ReflectionUtils.cloneOrDeepCopyIfNotImmutable(obj);
548 
549             // Treshold:     1
550             assertNotNull(obj.level1FieldClass);
551             assertNotNull(clonedObj.level1FieldClass);
552 
553             // Reset: very important!
554             ReflectionUtils.RECURSIVE_COPYING_DEPTH_TRESHOLD = 3;
555         }
556     }
557 
558 
559     public void testCloneOrDeepCopyIfNotImmutable_NoDefaultConstructor_NotMutable() {
560         Integer integer42 = 42;
561         Integer clonedInteger42 = ReflectionUtils.cloneOrDeepCopyIfNotImmutable(integer42);
562         assertSame(integer42, clonedInteger42);
563     }
564 
565 
566     public void testCloneOrDeepCopyIfNotImmutable_NoDefaultConstructor_Mutable() {
567         File file = new File("myFile.txt");
568         File clonedInteger42 = ReflectionUtils.cloneOrDeepCopyIfNotImmutable(file);
569 
570         /* Should not be same, but unable to deep copy objects with no available default constructor
571            Logs a WARN message */
572         //assertNotSame(file, clonedInteger42);
573         assertSame(file, clonedInteger42);
574     }
575 }
576 
577 
578 class ClassWithFieldOfSameType {
579     final long id = RandomUtils.nextLong();
580     ClassWithFieldOfSameType sameTypeRef;
581 
582     @Override
583     public boolean equals(final Object otherObj) {
584         if (otherObj == null) { return false; }
585         if (!(otherObj instanceof ClassWithFieldOfSameType)) { return false; }
586         ClassWithFieldOfSameType otherCastedObj = (ClassWithFieldOfSameType) otherObj;
587         return new EqualsBuilder().append(this.id, otherCastedObj.id).isEquals();
588     }
589 }
590 
591 
592 class ClassWithCustomerArray {
593     final long id = RandomUtils.nextLong();
594     final Customer[] customerArray = new Customer[2];
595 
596     @Override
597     public boolean equals(final Object otherObj) {
598         if (otherObj == null) { return false; }
599         if (!(otherObj instanceof ClassWithCustomerArray)) { return false; }
600         ClassWithCustomerArray otherCastedObj = (ClassWithCustomerArray) otherObj;
601         return new EqualsBuilder().append(this.id, otherCastedObj.id).isEquals();
602     }
603 }
604 
605 
606 class ClassWithFieldArrayOfSameType {
607     long id = RandomUtils.nextLong();
608     ClassWithFieldArrayOfSameType[] fieldArrayOfSameType = new ClassWithFieldArrayOfSameType[2];
609 
610     @Override
611     public boolean equals(final Object otherObj) {
612         if (otherObj == null) { return false; }
613         if (!(otherObj instanceof ClassWithFieldArrayOfSameType)) { return false; }
614         ClassWithFieldArrayOfSameType otherCastedObj = (ClassWithFieldArrayOfSameType) otherObj;
615         return new EqualsBuilder().append(this.id, otherCastedObj.id).isEquals();
616     }
617 }
618 
619 
620 class Level0FieldClass {
621     final Level1FieldClass level1FieldClass = new Level1FieldClass();
622 
623     @Override
624     public boolean equals(final Object otherObj) {
625         if (otherObj == null) { return false; }
626         if (!(otherObj instanceof Level0FieldClass)) { return false; }
627         Level0FieldClass otherCastedObj = (Level0FieldClass) otherObj;
628         return new EqualsBuilder().append(this.level1FieldClass, otherCastedObj.level1FieldClass).isEquals();
629     }
630 }
631 
632 
633 class Level1FieldClass {
634     final Level2FieldClass level2FieldClass = new Level2FieldClass();
635 
636     @Override
637     public boolean equals(final Object otherObj) {
638         if (otherObj == null) { return false; }
639         if (!(otherObj instanceof Level1FieldClass)) { return false; }
640         Level1FieldClass otherCastedObj = (Level1FieldClass) otherObj;
641         return new EqualsBuilder().append(this.level2FieldClass, otherCastedObj.level2FieldClass).isEquals();
642     }
643 }
644 
645 
646 class Level2FieldClass {
647     final Level3FieldClass level3FieldClass = new Level3FieldClass();
648 
649     @Override
650     public boolean equals(final Object otherObj) {
651         if (otherObj == null) { return false; }
652         if (!(otherObj instanceof Level2FieldClass)) { return false; }
653         Level2FieldClass otherCastedObj = (Level2FieldClass) otherObj;
654         return new EqualsBuilder().append(this.level3FieldClass, otherCastedObj.level3FieldClass).isEquals();
655     }
656 }
657 
658 
659 class Level3FieldClass {
660     final Level4FieldClass level4FieldClass = new Level4FieldClass();
661 
662     @Override
663     public boolean equals(final Object otherObj) {
664         if (otherObj == null) { return false; }
665         if (!(otherObj instanceof Level3FieldClass)) { return false; }
666         Level3FieldClass otherCastedObj = (Level3FieldClass) otherObj;
667         return new EqualsBuilder().append(this.level4FieldClass, otherCastedObj.level4FieldClass).isEquals();
668     }
669 }
670 
671 
672 class Level4FieldClass {
673     final Level5FieldClass level5FieldClass = new Level5FieldClass();
674 
675     @Override
676     public boolean equals(final Object otherObj) {
677         if (otherObj == null) { return false; }
678         if (!(otherObj instanceof Level4FieldClass)) { return false; }
679         Level4FieldClass otherCastedObj = (Level4FieldClass) otherObj;
680         return new EqualsBuilder().append(this.level5FieldClass, otherCastedObj.level5FieldClass).isEquals();
681     }
682 }
683 
684 
685 class Level5FieldClass {
686     final Level6FieldClass level6FieldClass = new Level6FieldClass();
687 
688     @Override
689     public boolean equals(final Object otherObj) {
690         if (otherObj == null) { return false; }
691         if (!(otherObj instanceof Level5FieldClass)) { return false; }
692         Level5FieldClass otherCastedObj = (Level5FieldClass) otherObj;
693         return new EqualsBuilder().append(this.level6FieldClass, otherCastedObj.level6FieldClass).isEquals();
694     }
695 }
696 
697 
698 class Level6FieldClass {}