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