1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package net.sf.oness.common.model.bo;
17
18 import java.lang.reflect.AccessibleObject;
19 import java.lang.reflect.Field;
20 import java.lang.reflect.Modifier;
21 import java.util.Collection;
22
23 import org.apache.commons.lang.builder.HashCodeBuilder;
24 import org.apache.commons.logging.Log;
25 import org.apache.commons.logging.LogFactory;
26
27 /***
28 * <p>Customized EqualsBuilder ignoring Collection fields.</p>
29 *
30 * <p>Only append(Object, Object) was modified</p>
31 *
32 * @author Carlos Sanchez
33 * @author Stephen Colebourne
34 * @author Gary Gregory
35 * @author Pete Gieser
36 * @version $Revision: 1.1 $
37 */
38 public class CollectionIgnoringHashCodeBuilder extends HashCodeBuilder {
39
40 private static Log log = LogFactory
41 .getLog(ExceptionSafeEqualsBuilder.class);
42
43 /***
44 * Constant to use in building the hashCode.
45 */
46 private final int iConstant;
47
48 /***
49 * Running total of the hashCode.
50 */
51 private int iTotal = 0;
52
53 /***
54 * <p>
55 * Constructor.
56 * </p>
57 *
58 * <p>
59 * This constructor uses two hard coded choices for the constants needed to
60 * build a <code>hashCode</code>.
61 * </p>
62 */
63 public CollectionIgnoringHashCodeBuilder() {
64 super();
65 iConstant = 37;
66 iTotal = 17;
67 }
68
69 /***
70 * <p>
71 * Constructor.
72 * </p>
73 *
74 * <p>
75 * Two randomly chosen, non-zero, odd numbers must be passed in. Ideally
76 * these should be different for each class, however this is not vital.
77 * </p>
78 *
79 * <p>
80 * Prime numbers are preferred, especially for the multiplier.
81 * </p>
82 *
83 * @param initialNonZeroOddNumber
84 * a non-zero, odd number used as the initial value
85 * @param multiplierNonZeroOddNumber
86 * a non-zero, odd number used as the multiplier
87 * @throws IllegalArgumentException
88 * if the number is zero or even
89 */
90 public CollectionIgnoringHashCodeBuilder(int initialNonZeroOddNumber,
91 int multiplierNonZeroOddNumber) {
92 super();
93 if (initialNonZeroOddNumber == 0) {
94 throw new IllegalArgumentException(
95 "HashCodeBuilder requires a non zero initial value");
96 }
97 if (initialNonZeroOddNumber % 2 == 0) {
98 throw new IllegalArgumentException(
99 "HashCodeBuilder requires an odd initial value");
100 }
101 if (multiplierNonZeroOddNumber == 0) {
102 throw new IllegalArgumentException(
103 "HashCodeBuilder requires a non zero multiplier");
104 }
105 if (multiplierNonZeroOddNumber % 2 == 0) {
106 throw new IllegalArgumentException(
107 "HashCodeBuilder requires an odd multiplier");
108 }
109 iConstant = multiplierNonZeroOddNumber;
110 iTotal = initialNonZeroOddNumber;
111 }
112
113
114
115 /***
116 * <p>
117 * This method uses reflection to build a valid hash code.
118 * </p>
119 *
120 * <p>
121 * This constructor uses two hard coded choices for the constants needed to
122 * build a hash code.
123 * </p>
124 *
125 * <p>
126 * It uses <code>AccessibleObject.setAccessible</code> to gain access to
127 * private fields. This means that it will throw a security exception if run
128 * under a security manager, if the permissions are not set up correctly. It
129 * is also not as efficient as testing explicitly.
130 * </p>
131 *
132 * <p>
133 * Transient members will be not be used, as they are likely derived fields,
134 * and not part of the value of the <code>Object</code>.
135 * </p>
136 *
137 * <p>
138 * Static fields will not be tested. Superclass fields will be included.
139 * </p>
140 *
141 * @param object
142 * the Object to create a <code>hashCode</code> for
143 * @return int hash code
144 * @throws IllegalArgumentException
145 * if the object is <code>null</code>
146 */
147 public static int reflectionHashCode(Object object) {
148 return reflectionHashCode(17, 37, object, false, null);
149 }
150
151 /***
152 * <p>
153 * This method uses reflection to build a valid hash code.
154 * </p>
155 *
156 * <p>
157 * This constructor uses two hard coded choices for the constants needed to
158 * build a hash code.
159 * </p>
160 *
161 * <p>
162 * It uses <code>AccessibleObject.setAccessible</code> to gain access to
163 * private fields. This means that it will throw a security exception if run
164 * under a security manager, if the permissions are not set up correctly. It
165 * is also not as efficient as testing explicitly.
166 * </p>
167 *
168 * <P>
169 * If the TestTransients parameter is set to <code>true</code>, transient
170 * members will be tested, otherwise they are ignored, as they are likely
171 * derived fields, and not part of the value of the <code>Object</code>.
172 * </p>
173 *
174 * <p>
175 * Static fields will not be tested. Superclass fields will be included.
176 * </p>
177 *
178 * @param object
179 * the Object to create a <code>hashCode</code> for
180 * @param testTransients
181 * whether to include transient fields
182 * @return int hash code
183 * @throws IllegalArgumentException
184 * if the object is <code>null</code>
185 */
186 public static int reflectionHashCode(Object object, boolean testTransients) {
187 return reflectionHashCode(17, 37, object, testTransients, null);
188 }
189
190 /***
191 * <p>
192 * This method uses reflection to build a valid hash code.
193 * </p>
194 *
195 * <p>
196 * It uses <code>AccessibleObject.setAccessible</code> to gain access to
197 * private fields. This means that it will throw a security exception if run
198 * under a security manager, if the permissions are not set up correctly. It
199 * is also not as efficient as testing explicitly.
200 * </p>
201 *
202 * <p>
203 * Transient members will be not be used, as they are likely derived fields,
204 * and not part of the value of the <code>Object</code>.
205 * </p>
206 *
207 * <p>
208 * Static fields will not be tested. Superclass fields will be included.
209 * </p>
210 *
211 * <p>
212 * Two randomly chosen, non-zero, odd numbers must be passed in. Ideally
213 * these should be different for each class, however this is not vital.
214 * Prime numbers are preferred, especially for the multiplier.
215 * </p>
216 *
217 * @param initialNonZeroOddNumber
218 * a non-zero, odd number used as the initial value
219 * @param multiplierNonZeroOddNumber
220 * a non-zero, odd number used as the multiplier
221 * @param object
222 * the Object to create a <code>hashCode</code> for
223 * @return int hash code
224 * @throws IllegalArgumentException
225 * if the Object is <code>null</code>
226 * @throws IllegalArgumentException
227 * if the number is zero or even
228 */
229 public static int reflectionHashCode(int initialNonZeroOddNumber,
230 int multiplierNonZeroOddNumber, Object object) {
231 return reflectionHashCode(initialNonZeroOddNumber,
232 multiplierNonZeroOddNumber, object, false, null);
233 }
234
235 /***
236 * <p>
237 * This method uses reflection to build a valid hash code.
238 * </p>
239 *
240 * <p>
241 * It uses <code>AccessibleObject.setAccessible</code> to gain access to
242 * private fields. This means that it will throw a security exception if run
243 * under a security manager, if the permissions are not set up correctly. It
244 * is also not as efficient as testing explicitly.
245 * </p>
246 *
247 * <p>
248 * If the TestTransients parameter is set to <code>true</code>, transient
249 * members will be tested, otherwise they are ignored, as they are likely
250 * derived fields, and not part of the value of the <code>Object</code>.
251 * </p>
252 *
253 * <p>
254 * Static fields will not be tested. Superclass fields will be included.
255 * </p>
256 *
257 * <p>
258 * Two randomly chosen, non-zero, odd numbers must be passed in. Ideally
259 * these should be different for each class, however this is not vital.
260 * Prime numbers are preferred, especially for the multiplier.
261 * </p>
262 *
263 * @param initialNonZeroOddNumber
264 * a non-zero, odd number used as the initial value
265 * @param multiplierNonZeroOddNumber
266 * a non-zero, odd number used as the multiplier
267 * @param object
268 * the Object to create a <code>hashCode</code> for
269 * @param testTransients
270 * whether to include transient fields
271 * @return int hash code
272 * @throws IllegalArgumentException
273 * if the Object is <code>null</code>
274 * @throws IllegalArgumentException
275 * if the number is zero or even
276 */
277 public static int reflectionHashCode(int initialNonZeroOddNumber,
278 int multiplierNonZeroOddNumber, Object object,
279 boolean testTransients) {
280 return reflectionHashCode(initialNonZeroOddNumber,
281 multiplierNonZeroOddNumber, object, testTransients, null);
282 }
283
284 /***
285 * <p>
286 * This method uses reflection to build a valid hash code.
287 * </p>
288 *
289 * <p>
290 * It uses <code>AccessibleObject.setAccessible</code> to gain access to
291 * private fields. This means that it will throw a security exception if run
292 * under a security manager, if the permissions are not set up correctly. It
293 * is also not as efficient as testing explicitly.
294 * </p>
295 *
296 * <p>
297 * If the TestTransients parameter is set to <code>true</code>, transient
298 * members will be tested, otherwise they are ignored, as they are likely
299 * derived fields, and not part of the value of the <code>Object</code>.
300 * </p>
301 *
302 * <p>
303 * Static fields will not be included. Superclass fields will be included up
304 * to and including the specified superclass. A null superclass is treated
305 * as java.lang.Object.
306 * </p>
307 *
308 * <p>
309 * Two randomly chosen, non-zero, odd numbers must be passed in. Ideally
310 * these should be different for each class, however this is not vital.
311 * Prime numbers are preferred, especially for the multiplier.
312 * </p>
313 *
314 * @param initialNonZeroOddNumber
315 * a non-zero, odd number used as the initial value
316 * @param multiplierNonZeroOddNumber
317 * a non-zero, odd number used as the multiplier
318 * @param object
319 * the Object to create a <code>hashCode</code> for
320 * @param testTransients
321 * whether to include transient fields
322 * @param reflectUpToClass
323 * the superclass to reflect up to (inclusive), may be
324 * <code>null</code>
325 * @return int hash code
326 * @throws IllegalArgumentException
327 * if the Object is <code>null</code>
328 * @throws IllegalArgumentException
329 * if the number is zero or even
330 * @since 2.0
331 */
332 public static int reflectionHashCode(int initialNonZeroOddNumber,
333 int multiplierNonZeroOddNumber, Object object,
334 boolean testTransients, Class reflectUpToClass) {
335
336 if (object == null) {
337 throw new IllegalArgumentException(
338 "The object to build a hash code for must not be null");
339 }
340 HashCodeBuilder builder = new CollectionIgnoringHashCodeBuilder(
341 initialNonZeroOddNumber, multiplierNonZeroOddNumber);
342 Class clazz = object.getClass();
343 reflectionAppend(object, clazz, builder, testTransients);
344 while (clazz.getSuperclass() != null && clazz != reflectUpToClass) {
345 clazz = clazz.getSuperclass();
346 reflectionAppend(object, clazz, builder, testTransients);
347 }
348 return builder.toHashCode();
349 }
350
351 /***
352 * <p>
353 * Appends the fields and values defined by the given object of the given
354 * <code>Class</code>.
355 * </p>
356 *
357 * @param object
358 * the object to append details of
359 * @param clazz
360 * the class to append details of
361 * @param builder
362 * the builder to append to
363 * @param useTransients
364 * whether to use transient fields
365 */
366 private static void reflectionAppend(Object object, Class clazz,
367 HashCodeBuilder builder, boolean useTransients) {
368 Field[] fields = clazz.getDeclaredFields();
369 AccessibleObject.setAccessible(fields, true);
370 for (int i = 0; i < fields.length; i++) {
371 Field f = fields[i];
372 if ((f.getName().indexOf('$') == -1)
373 && (useTransients || !Modifier
374 .isTransient(f.getModifiers()))
375 && (!Modifier.isStatic(f.getModifiers()))) {
376 try {
377 builder.append(f.get(object));
378 } catch (IllegalAccessException e) {
379
380
381 throw new InternalError("Unexpected IllegalAccessException");
382 }
383 }
384 }
385 }
386
387
388
389 /***
390 * <p>
391 * Adds the result of super.hashCode() to this builder.
392 * </p>
393 *
394 * @param superHashCode
395 * the result of calling <code>super.hashCode()</code>
396 * @return this HashCodeBuilder, used to chain calls.
397 * @since 2.0
398 */
399 public HashCodeBuilder appendSuper(int superHashCode) {
400 iTotal = iTotal * iConstant + superHashCode;
401 return this;
402 }
403
404
405
406 /***
407 * <p>
408 * Append a <code>hashCode</code> for an <code>Object</code>.
409 * Collections are ignored.
410 * </p>
411 *
412 * @param object
413 * the Object to add to the <code>hashCode</code>
414 * @return this
415 */
416 public HashCodeBuilder append(Object object) {
417
418 /******************************************************/
419 if (object instanceof Collection) {
420 iTotal = iTotal * iConstant;
421 return this;
422 }
423 /******************************************************/
424
425 if (object == null) {
426 iTotal = iTotal * iConstant;
427
428 } else {
429 if (object.getClass().isArray() == false) {
430
431
432
433
434 if (!(object instanceof Collection)) {
435 try {
436
437
438 iTotal = iTotal * iConstant + object.hashCode();
439
440 } catch (Exception e) {
441
442 if (log.isDebugEnabled()) {
443 log
444 .debug("Ignored field in hashCode method due to exception: "
445 + e.getLocalizedMessage());
446 }
447 }
448 }
449
450
451
452 } else {
453
454
455 if (object instanceof long[]) {
456 append((long[]) object);
457 } else if (object instanceof int[]) {
458 append((int[]) object);
459 } else if (object instanceof short[]) {
460 append((short[]) object);
461 } else if (object instanceof char[]) {
462 append((char[]) object);
463 } else if (object instanceof byte[]) {
464 append((byte[]) object);
465 } else if (object instanceof double[]) {
466 append((double[]) object);
467 } else if (object instanceof float[]) {
468 append((float[]) object);
469 } else if (object instanceof boolean[]) {
470 append((boolean[]) object);
471 } else {
472
473 append((Object[]) object);
474 }
475 }
476 }
477 return this;
478 }
479
480 /***
481 * <p>
482 * Append a <code>hashCode</code> for a <code>long</code>.
483 * </p>
484 *
485 * @param value
486 * the long to add to the <code>hashCode</code>
487 * @return this
488 */
489 public HashCodeBuilder append(long value) {
490 iTotal = iTotal * iConstant + ((int) (value ^ (value >> 32)));
491 return this;
492 }
493
494 /***
495 * <p>
496 * Append a <code>hashCode</code> for an <code>int</code>.
497 * </p>
498 *
499 * @param value
500 * the int to add to the <code>hashCode</code>
501 * @return this
502 */
503 public HashCodeBuilder append(int value) {
504 iTotal = iTotal * iConstant + value;
505 return this;
506 }
507
508 /***
509 * <p>
510 * Append a <code>hashCode</code> for a <code>short</code>.
511 * </p>
512 *
513 * @param value
514 * the short to add to the <code>hashCode</code>
515 * @return this
516 */
517 public HashCodeBuilder append(short value) {
518 iTotal = iTotal * iConstant + value;
519 return this;
520 }
521
522 /***
523 * <p>
524 * Append a <code>hashCode</code> for a <code>char</code>.
525 * </p>
526 *
527 * @param value
528 * the char to add to the <code>hashCode</code>
529 * @return this
530 */
531 public HashCodeBuilder append(char value) {
532 iTotal = iTotal * iConstant + value;
533 return this;
534 }
535
536 /***
537 * <p>
538 * Append a <code>hashCode</code> for a <code>byte</code>.
539 * </p>
540 *
541 * @param value
542 * the byte to add to the <code>hashCode</code>
543 * @return this
544 */
545 public HashCodeBuilder append(byte value) {
546 iTotal = iTotal * iConstant + value;
547 return this;
548 }
549
550 /***
551 * <p>
552 * Append a <code>hashCode</code> for a <code>double</code>.
553 * </p>
554 *
555 * @param value
556 * the double to add to the <code>hashCode</code>
557 * @return this
558 */
559 public HashCodeBuilder append(double value) {
560 return append(Double.doubleToLongBits(value));
561 }
562
563 /***
564 * <p>
565 * Append a <code>hashCode</code> for a <code>float</code>.
566 * </p>
567 *
568 * @param value
569 * the float to add to the <code>hashCode</code>
570 * @return this
571 */
572 public HashCodeBuilder append(float value) {
573 iTotal = iTotal * iConstant + Float.floatToIntBits(value);
574 return this;
575 }
576
577 /***
578 * <p>
579 * Append a <code>hashCode</code> for a <code>boolean</code>.
580 * </p>
581 *
582 * @param value
583 * the boolean to add to the <code>hashCode</code>
584 * @return this
585 */
586 public HashCodeBuilder append(boolean value) {
587 iTotal = iTotal * iConstant + (value ? 0 : 1);
588 return this;
589 }
590
591 /***
592 * <p>
593 * Append a <code>hashCode</code> for an <code>Object</code> array.
594 * </p>
595 *
596 * @param array
597 * the array to add to the <code>hashCode</code>
598 * @return this
599 */
600 public HashCodeBuilder append(Object[] array) {
601 if (array == null) {
602 iTotal = iTotal * iConstant;
603 } else {
604 for (int i = 0; i < array.length; i++) {
605 append(array[i]);
606 }
607 }
608 return this;
609 }
610
611 /***
612 * <p>
613 * Append a <code>hashCode</code> for a <code>long</code> array.
614 * </p>
615 *
616 * @param array
617 * the array to add to the <code>hashCode</code>
618 * @return this
619 */
620 public HashCodeBuilder append(long[] array) {
621 if (array == null) {
622 iTotal = iTotal * iConstant;
623 } else {
624 for (int i = 0; i < array.length; i++) {
625 append(array[i]);
626 }
627 }
628 return this;
629 }
630
631 /***
632 * <p>
633 * Append a <code>hashCode</code> for an <code>int</code> array.
634 * </p>
635 *
636 * @param array
637 * the array to add to the <code>hashCode</code>
638 * @return this
639 */
640 public HashCodeBuilder append(int[] array) {
641 if (array == null) {
642 iTotal = iTotal * iConstant;
643 } else {
644 for (int i = 0; i < array.length; i++) {
645 append(array[i]);
646 }
647 }
648 return this;
649 }
650
651 /***
652 * <p>
653 * Append a <code>hashCode</code> for a <code>short</code> array.
654 * </p>
655 *
656 * @param array
657 * the array to add to the <code>hashCode</code>
658 * @return this
659 */
660 public HashCodeBuilder append(short[] array) {
661 if (array == null) {
662 iTotal = iTotal * iConstant;
663 } else {
664 for (int i = 0; i < array.length; i++) {
665 append(array[i]);
666 }
667 }
668 return this;
669 }
670
671 /***
672 * <p>
673 * Append a <code>hashCode</code> for a <code>char</code> array.
674 * </p>
675 *
676 * @param array
677 * the array to add to the <code>hashCode</code>
678 * @return this
679 */
680 public HashCodeBuilder append(char[] array) {
681 if (array == null) {
682 iTotal = iTotal * iConstant;
683 } else {
684 for (int i = 0; i < array.length; i++) {
685 append(array[i]);
686 }
687 }
688 return this;
689 }
690
691 /***
692 * <p>
693 * Append a <code>hashCode</code> for a <code>byte</code> array.
694 * </p>
695 *
696 * @param array
697 * the array to add to the <code>hashCode</code>
698 * @return this
699 */
700 public HashCodeBuilder append(byte[] array) {
701 if (array == null) {
702 iTotal = iTotal * iConstant;
703 } else {
704 for (int i = 0; i < array.length; i++) {
705 append(array[i]);
706 }
707 }
708 return this;
709 }
710
711 /***
712 * <p>
713 * Append a <code>hashCode</code> for a <code>double</code> array.
714 * </p>
715 *
716 * @param array
717 * the array to add to the <code>hashCode</code>
718 * @return this
719 */
720 public HashCodeBuilder append(double[] array) {
721 if (array == null) {
722 iTotal = iTotal * iConstant;
723 } else {
724 for (int i = 0; i < array.length; i++) {
725 append(array[i]);
726 }
727 }
728 return this;
729 }
730
731 /***
732 * <p>
733 * Append a <code>hashCode</code> for a <code>float</code> array.
734 * </p>
735 *
736 * @param array
737 * the array to add to the <code>hashCode</code>
738 * @return this
739 */
740 public HashCodeBuilder append(float[] array) {
741 if (array == null) {
742 iTotal = iTotal * iConstant;
743 } else {
744 for (int i = 0; i < array.length; i++) {
745 append(array[i]);
746 }
747 }
748 return this;
749 }
750
751 /***
752 * <p>
753 * Append a <code>hashCode</code> for a <code>boolean</code> array.
754 * </p>
755 *
756 * @param array
757 * the array to add to the <code>hashCode</code>
758 * @return this
759 */
760 public HashCodeBuilder append(boolean[] array) {
761 if (array == null) {
762 iTotal = iTotal * iConstant;
763 } else {
764 for (int i = 0; i < array.length; i++) {
765 append(array[i]);
766 }
767 }
768 return this;
769 }
770
771 /***
772 * <p>
773 * Return the computed <code>hashCode</code>.
774 * </p>
775 *
776 * @return <code>hashCode</code> based on the fields appended
777 */
778 public int toHashCode() {
779 return iTotal;
780 }
781
782 }