1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package org.apache.commons.lang3.builder;
19
20 import java.lang.reflect.AccessibleObject;
21 import java.lang.reflect.Field;
22 import java.lang.reflect.Modifier;
23 import java.util.Collection;
24 import java.util.Comparator;
25 import java.util.HashSet;
26 import java.util.Objects;
27 import java.util.Set;
28
29 import org.apache.commons.lang3.ArraySorter;
30 import org.apache.commons.lang3.ArrayUtils;
31 import org.apache.commons.lang3.ObjectUtils;
32 import org.apache.commons.lang3.Validate;
33
34 /**
35 * Assists in implementing {@link Object#hashCode()} methods.
36 *
37 * <p>
38 * This class enables a good {@code hashCode} method to be built for any class. It follows the rules laid out in
39 * the book <a href="https://www.oracle.com/technetwork/java/effectivejava-136174.html">Effective Java</a> by Joshua Bloch. Writing a
40 * good {@code hashCode} method is actually quite difficult. This class aims to simplify the process.
41 * </p>
42 *
43 * <p>
44 * The following is the approach taken. When appending a data field, the current total is multiplied by the
45 * multiplier then a relevant value
46 * for that data type is added. For example, if the current hashCode is 17, and the multiplier is 37, then
47 * appending the integer 45 will create a hash code of 674, namely 17 * 37 + 45.
48 * </p>
49 *
50 * <p>
51 * All relevant fields from the object should be included in the {@code hashCode} method. Derived fields may be
52 * excluded. In general, any field used in the {@code equals} method must be used in the {@code hashCode}
53 * method.
54 * </p>
55 *
56 * <p>
57 * To use this class write code as follows:
58 * </p>
59 *
60 * <pre>
61 * public class Person {
62 * String name;
63 * int age;
64 * boolean smoker;
65 * ...
66 *
67 * public int hashCode() {
68 * // you pick a hard-coded, randomly chosen, non-zero, odd number
69 * // ideally different for each class
70 * return new HashCodeBuilder(17, 37).
71 * append(name).
72 * append(age).
73 * append(smoker).
74 * toHashCode();
75 * }
76 * }
77 * </pre>
78 *
79 * <p>
80 * If required, the superclass {@code hashCode()} can be added using {@link #appendSuper}.
81 * </p>
82 *
83 * <p>
84 * Alternatively, there is a method that uses reflection to determine the fields to test. Because these fields are
85 * usually private, the method, {@code reflectionHashCode}, uses {@code AccessibleObject.setAccessible}
86 * to change the visibility of the fields. This will fail under a security manager, unless the appropriate permissions
87 * are set up correctly. It is also slower than testing explicitly.
88 * </p>
89 *
90 * <p>
91 * A typical invocation for this method would look like:
92 * </p>
93 *
94 * <pre>
95 * public int hashCode() {
96 * return HashCodeBuilder.reflectionHashCode(this);
97 * }
98 * </pre>
99 *
100 * <p>The {@link HashCodeExclude} annotation can be used to exclude fields from being
101 * used by the {@code reflectionHashCode} methods.</p>
102 *
103 * @since 1.0
104 */
105 public class HashCodeBuilder implements Builder<Integer> {
106 /**
107 * The default initial value to use in reflection hash code building.
108 */
109 private static final int DEFAULT_INITIAL_VALUE = 17;
110
111 /**
112 * The default multiplier value to use in reflection hash code building.
113 */
114 private static final int DEFAULT_MULTIPLIER_VALUE = 37;
115
116 /**
117 * A registry of objects used by reflection methods to detect cyclical object references and avoid infinite loops.
118 *
119 * @since 2.3
120 */
121 private static final ThreadLocal<Set<IDKey>> REGISTRY = ThreadLocal.withInitial(HashSet::new);
122
123 /*
124 * NOTE: we cannot store the actual objects in a HashSet, as that would use the very hashCode()
125 * we are in the process of calculating.
126 *
127 * So we generate a one-to-one mapping from the original object to a new object.
128 *
129 * Now HashSet uses equals() to determine if two elements with the same hash code really
130 * are equal, so we also need to ensure that the replacement objects are only equal
131 * if the original objects are identical.
132 *
133 * The original implementation (2.4 and before) used the System.identityHashCode()
134 * method - however this is not guaranteed to generate unique ids (e.g. LANG-459)
135 *
136 * We now use the IDKey helper class (adapted from org.apache.axis.utils.IDKey)
137 * to disambiguate the duplicate ids.
138 */
139
140 /**
141 * Gets the registry of objects being traversed by the reflection methods in the current thread.
142 *
143 * @return Set the registry of objects being traversed
144 * @since 2.3
145 */
146 static Set<IDKey> getRegistry() {
147 return REGISTRY.get();
148 }
149
150 /**
151 * Tests whether the registry contains the given object. Used by the reflection methods to avoid
152 * infinite loops.
153 *
154 * @param value
155 * The object to lookup in the registry.
156 * @return boolean {@code true} if the registry contains the given object.
157 * @since 2.3
158 */
159 static boolean isRegistered(final Object value) {
160 final Set<IDKey> registry = getRegistry();
161 return registry != null && registry.contains(new IDKey(value));
162 }
163
164 /**
165 * Appends the fields and values defined by the given object of the given {@link Class}.
166 *
167 * @param object
168 * the object to append details of
169 * @param clazz
170 * the class to append details of
171 * @param builder
172 * the builder to append to
173 * @param useTransients
174 * whether to use transient fields
175 * @param excludeFields
176 * Collection of String field names to exclude from use in calculation of hash code
177 */
178 private static void reflectionAppend(final Object object, final Class<?> clazz, final HashCodeBuilder builder, final boolean useTransients,
179 final String[] excludeFields) {
180 if (isRegistered(object)) {
181 return;
182 }
183 try {
184 register(object);
185 // The elements in the returned array are not sorted and are not in any particular order.
186 final Field[] fields = ArraySorter.sort(clazz.getDeclaredFields(), Comparator.comparing(Field::getName));
187 AccessibleObject.setAccessible(fields, true);
188 for (final Field field : fields) {
189 if (!ArrayUtils.contains(excludeFields, field.getName())
190 && !field.getName().contains("$")
191 && (useTransients || !Modifier.isTransient(field.getModifiers()))
192 && !Modifier.isStatic(field.getModifiers())
193 && !field.isAnnotationPresent(HashCodeExclude.class)) {
194 builder.append(Reflection.getUnchecked(field, object));
195 }
196 }
197 } finally {
198 unregister(object);
199 }
200 }
201
202 /**
203 * Uses reflection to build a valid hash code from the fields of {@code object}.
204 *
205 * <p>
206 * It uses {@code AccessibleObject.setAccessible} to gain access to private fields. This means that it will
207 * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
208 * also not as efficient as testing explicitly.
209 * </p>
210 *
211 * <p>
212 * Transient members will be not be used, as they are likely derived fields, and not part of the value of the
213 * {@link Object}.
214 * </p>
215 *
216 * <p>
217 * Static fields will not be tested. Superclass fields will be included.
218 * </p>
219 *
220 * <p>
221 * Two randomly chosen, non-zero, odd numbers must be passed in. Ideally these should be different for each class,
222 * however this is not vital. Prime numbers are preferred, especially for the multiplier.
223 * </p>
224 *
225 * @param initialNonZeroOddNumber
226 * a non-zero, odd number used as the initial value. This will be the returned
227 * value if no fields are found to include in the hash code
228 * @param multiplierNonZeroOddNumber
229 * a non-zero, odd number used as the multiplier
230 * @param object
231 * the Object to create a {@code hashCode} for
232 * @return int hash code
233 * @throws NullPointerException
234 * if the Object is {@code null}
235 * @throws IllegalArgumentException
236 * if the number is zero or even
237 *
238 * @see HashCodeExclude
239 */
240 public static int reflectionHashCode(final int initialNonZeroOddNumber, final int multiplierNonZeroOddNumber, final Object object) {
241 return reflectionHashCode(initialNonZeroOddNumber, multiplierNonZeroOddNumber, object, false, null);
242 }
243
244 /**
245 * Uses reflection to build a valid hash code from the fields of {@code object}.
246 *
247 * <p>
248 * It uses {@code AccessibleObject.setAccessible} to gain access to private fields. This means that it will
249 * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
250 * also not as efficient as testing explicitly.
251 * </p>
252 *
253 * <p>
254 * If the TestTransients parameter is set to {@code true}, transient members will be tested, otherwise they
255 * are ignored, as they are likely derived fields, and not part of the value of the {@link Object}.
256 * </p>
257 *
258 * <p>
259 * Static fields will not be tested. Superclass fields will be included.
260 * </p>
261 *
262 * <p>
263 * Two randomly chosen, non-zero, odd numbers must be passed in. Ideally these should be different for each class,
264 * however this is not vital. Prime numbers are preferred, especially for the multiplier.
265 * </p>
266 *
267 * @param initialNonZeroOddNumber
268 * a non-zero, odd number used as the initial value. This will be the returned
269 * value if no fields are found to include in the hash code
270 * @param multiplierNonZeroOddNumber
271 * a non-zero, odd number used as the multiplier
272 * @param object
273 * the Object to create a {@code hashCode} for
274 * @param testTransients
275 * whether to include transient fields
276 * @return int hash code
277 * @throws NullPointerException
278 * if the Object is {@code null}
279 * @throws IllegalArgumentException
280 * if the number is zero or even
281 *
282 * @see HashCodeExclude
283 */
284 public static int reflectionHashCode(final int initialNonZeroOddNumber, final int multiplierNonZeroOddNumber, final Object object,
285 final boolean testTransients) {
286 return reflectionHashCode(initialNonZeroOddNumber, multiplierNonZeroOddNumber, object, testTransients, null);
287 }
288
289 /**
290 * Uses reflection to build a valid hash code from the fields of {@code object}.
291 *
292 * <p>
293 * It uses {@code AccessibleObject.setAccessible} to gain access to private fields. This means that it will
294 * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
295 * also not as efficient as testing explicitly.
296 * </p>
297 *
298 * <p>
299 * If the TestTransients parameter is set to {@code true}, transient members will be tested, otherwise they
300 * are ignored, as they are likely derived fields, and not part of the value of the {@link Object}.
301 * </p>
302 *
303 * <p>
304 * Static fields will not be included. Superclass fields will be included up to and including the specified
305 * superclass. A null superclass is treated as java.lang.Object.
306 * </p>
307 *
308 * <p>
309 * Two randomly chosen, non-zero, odd numbers must be passed in. Ideally these should be different for each class,
310 * however this is not vital. Prime numbers are preferred, especially for the multiplier.
311 * </p>
312 *
313 * @param <T>
314 * the type of the object involved
315 * @param initialNonZeroOddNumber
316 * a non-zero, odd number used as the initial value. This will be the returned
317 * value if no fields are found to include in the hash code
318 * @param multiplierNonZeroOddNumber
319 * a non-zero, odd number used as the multiplier
320 * @param object
321 * the Object to create a {@code hashCode} for
322 * @param testTransients
323 * whether to include transient fields
324 * @param reflectUpToClass
325 * the superclass to reflect up to (inclusive), may be {@code null}
326 * @param excludeFields
327 * array of field names to exclude from use in calculation of hash code
328 * @return int hash code
329 * @throws NullPointerException
330 * if the Object is {@code null}
331 * @throws IllegalArgumentException
332 * if the number is zero or even
333 *
334 * @see HashCodeExclude
335 * @since 2.0
336 */
337 public static <T> int reflectionHashCode(final int initialNonZeroOddNumber, final int multiplierNonZeroOddNumber, final T object,
338 final boolean testTransients, final Class<? super T> reflectUpToClass, final String... excludeFields) {
339 Objects.requireNonNull(object, "object");
340 final HashCodeBuilder builder = new HashCodeBuilder(initialNonZeroOddNumber, multiplierNonZeroOddNumber);
341 Class<?> clazz = object.getClass();
342 reflectionAppend(object, clazz, builder, testTransients, excludeFields);
343 while (clazz.getSuperclass() != null && clazz != reflectUpToClass) {
344 clazz = clazz.getSuperclass();
345 reflectionAppend(object, clazz, builder, testTransients, excludeFields);
346 }
347 return builder.toHashCode();
348 }
349
350 /**
351 * Uses reflection to build a valid hash code from the fields of {@code object}.
352 *
353 * <p>
354 * This constructor uses two hard coded choices for the constants needed to build a hash code.
355 * </p>
356 *
357 * <p>
358 * It uses {@code AccessibleObject.setAccessible} to gain access to private fields. This means that it will
359 * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
360 * also not as efficient as testing explicitly.
361 * </p>
362 *
363 * <p>
364 * If the TestTransients parameter is set to {@code true}, transient members will be tested, otherwise they
365 * are ignored, as they are likely derived fields, and not part of the value of the {@link Object}.
366 * </p>
367 *
368 * <p>
369 * Static fields will not be tested. Superclass fields will be included. If no fields are found to include
370 * in the hash code, the result of this method will be constant.
371 * </p>
372 *
373 * @param object
374 * the Object to create a {@code hashCode} for
375 * @param testTransients
376 * whether to include transient fields
377 * @return int hash code
378 * @throws NullPointerException
379 * if the object is {@code null}
380 *
381 * @see HashCodeExclude
382 */
383 public static int reflectionHashCode(final Object object, final boolean testTransients) {
384 return reflectionHashCode(DEFAULT_INITIAL_VALUE, DEFAULT_MULTIPLIER_VALUE, object,
385 testTransients, null);
386 }
387
388 /**
389 * Uses reflection to build a valid hash code from the fields of {@code object}.
390 *
391 * <p>
392 * This constructor uses two hard coded choices for the constants needed to build a hash code.
393 * </p>
394 *
395 * <p>
396 * It uses {@code AccessibleObject.setAccessible} to gain access to private fields. This means that it will
397 * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
398 * also not as efficient as testing explicitly.
399 * </p>
400 *
401 * <p>
402 * Transient members will be not be used, as they are likely derived fields, and not part of the value of the
403 * {@link Object}.
404 * </p>
405 *
406 * <p>
407 * Static fields will not be tested. Superclass fields will be included. If no fields are found to include
408 * in the hash code, the result of this method will be constant.
409 * </p>
410 *
411 * @param object
412 * the Object to create a {@code hashCode} for
413 * @param excludeFields
414 * Collection of String field names to exclude from use in calculation of hash code
415 * @return int hash code
416 * @throws NullPointerException
417 * if the object is {@code null}
418 *
419 * @see HashCodeExclude
420 */
421 public static int reflectionHashCode(final Object object, final Collection<String> excludeFields) {
422 return reflectionHashCode(object, ReflectionToStringBuilder.toNoNullStringArray(excludeFields));
423 }
424
425 /**
426 * Uses reflection to build a valid hash code from the fields of {@code object}.
427 *
428 * <p>
429 * This constructor uses two hard coded choices for the constants needed to build a hash code.
430 * </p>
431 *
432 * <p>
433 * It uses {@code AccessibleObject.setAccessible} to gain access to private fields. This means that it will
434 * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
435 * also not as efficient as testing explicitly.
436 * </p>
437 *
438 * <p>
439 * Transient members will be not be used, as they are likely derived fields, and not part of the value of the
440 * {@link Object}.
441 * </p>
442 *
443 * <p>
444 * Static fields will not be tested. Superclass fields will be included. If no fields are found to include
445 * in the hash code, the result of this method will be constant.
446 * </p>
447 *
448 * @param object
449 * the Object to create a {@code hashCode} for
450 * @param excludeFields
451 * array of field names to exclude from use in calculation of hash code
452 * @return int hash code
453 * @throws NullPointerException
454 * if the object is {@code null}
455 *
456 * @see HashCodeExclude
457 */
458 public static int reflectionHashCode(final Object object, final String... excludeFields) {
459 return reflectionHashCode(DEFAULT_INITIAL_VALUE, DEFAULT_MULTIPLIER_VALUE, object, false,
460 null, excludeFields);
461 }
462
463 /**
464 * Registers the given object. Used by the reflection methods to avoid infinite loops.
465 *
466 * @param value
467 * The object to register.
468 */
469 private static void register(final Object value) {
470 getRegistry().add(new IDKey(value));
471 }
472
473 /**
474 * Unregisters the given object.
475 *
476 * <p>
477 * Used by the reflection methods to avoid infinite loops.
478 * </p>
479 *
480 * @param value
481 * The object to unregister.
482 * @since 2.3
483 */
484 private static void unregister(final Object value) {
485 final Set<IDKey> registry = getRegistry();
486 registry.remove(new IDKey(value));
487 if (registry.isEmpty()) {
488 REGISTRY.remove();
489 }
490 }
491
492 /**
493 * Constant to use in building the hashCode.
494 */
495 private final int iConstant;
496
497 /**
498 * Running total of the hashCode.
499 */
500 private int iTotal;
501
502 /**
503 * Uses two hard coded choices for the constants needed to build a {@code hashCode}.
504 */
505 public HashCodeBuilder() {
506 iConstant = 37;
507 iTotal = 17;
508 }
509
510 /**
511 * Two randomly chosen, odd numbers must be passed in. Ideally these should be different for each class,
512 * however this is not vital.
513 *
514 * <p>
515 * Prime numbers are preferred, especially for the multiplier.
516 * </p>
517 *
518 * @param initialOddNumber
519 * an odd number used as the initial value
520 * @param multiplierOddNumber
521 * an odd number used as the multiplier
522 * @throws IllegalArgumentException
523 * if the number is even
524 */
525 public HashCodeBuilder(final int initialOddNumber, final int multiplierOddNumber) {
526 Validate.isTrue(initialOddNumber % 2 != 0, "HashCodeBuilder requires an odd initial value");
527 Validate.isTrue(multiplierOddNumber % 2 != 0, "HashCodeBuilder requires an odd multiplier");
528 iConstant = multiplierOddNumber;
529 iTotal = initialOddNumber;
530 }
531
532 /**
533 * Append a {@code hashCode} for a {@code boolean}.
534 *
535 * <p>
536 * This adds {@code 1} when true, and {@code 0} when false to the {@code hashCode}.
537 * </p>
538 * <p>
539 * This is in contrast to the standard {@link Boolean#hashCode()} handling, which computes
540 * a {@code hashCode} value of {@code 1231} for {@link Boolean} instances
541 * that represent {@code true} or {@code 1237} for {@link Boolean} instances
542 * that represent {@code false}.
543 * </p>
544 * <p>
545 * This is in accordance with the <em>Effective Java</em> design.
546 * </p>
547 *
548 * @param value
549 * the boolean to add to the {@code hashCode}
550 * @return {@code this} instance.
551 */
552 public HashCodeBuilder append(final boolean value) {
553 iTotal = iTotal * iConstant + (value ? 0 : 1);
554 return this;
555 }
556
557 /**
558 * Append a {@code hashCode} for a {@code boolean} array.
559 *
560 * @param array
561 * the array to add to the {@code hashCode}
562 * @return {@code this} instance.
563 */
564 public HashCodeBuilder append(final boolean[] array) {
565 if (array == null) {
566 iTotal = iTotal * iConstant;
567 } else {
568 for (final boolean element : array) {
569 append(element);
570 }
571 }
572 return this;
573 }
574
575 /**
576 * Append a {@code hashCode} for a {@code byte}.
577 *
578 * @param value
579 * the byte to add to the {@code hashCode}
580 * @return {@code this} instance.
581 */
582 public HashCodeBuilder append(final byte value) {
583 iTotal = iTotal * iConstant + value;
584 return this;
585 }
586
587 /**
588 * Append a {@code hashCode} for a {@code byte} array.
589 *
590 * @param array
591 * the array to add to the {@code hashCode}
592 * @return {@code this} instance.
593 */
594 public HashCodeBuilder append(final byte[] array) {
595 if (array == null) {
596 iTotal = iTotal * iConstant;
597 } else {
598 for (final byte element : array) {
599 append(element);
600 }
601 }
602 return this;
603 }
604
605 /**
606 * Append a {@code hashCode} for a {@code char}.
607 *
608 * @param value
609 * the char to add to the {@code hashCode}
610 * @return {@code this} instance.
611 */
612 public HashCodeBuilder append(final char value) {
613 iTotal = iTotal * iConstant + value;
614 return this;
615 }
616
617 /**
618 * Append a {@code hashCode} for a {@code char} array.
619 *
620 * @param array
621 * the array to add to the {@code hashCode}
622 * @return {@code this} instance.
623 */
624 public HashCodeBuilder append(final char[] array) {
625 if (array == null) {
626 iTotal = iTotal * iConstant;
627 } else {
628 for (final char element : array) {
629 append(element);
630 }
631 }
632 return this;
633 }
634
635 /**
636 * Append a {@code hashCode} for a {@code double}.
637 *
638 * @param value
639 * the double to add to the {@code hashCode}
640 * @return {@code this} instance.
641 */
642 public HashCodeBuilder append(final double value) {
643 return append(Double.doubleToLongBits(value));
644 }
645
646 /**
647 * Append a {@code hashCode} for a {@code double} array.
648 *
649 * @param array
650 * the array to add to the {@code hashCode}
651 * @return {@code this} instance.
652 */
653 public HashCodeBuilder append(final double[] array) {
654 if (array == null) {
655 iTotal = iTotal * iConstant;
656 } else {
657 for (final double element : array) {
658 append(element);
659 }
660 }
661 return this;
662 }
663
664 /**
665 * Append a {@code hashCode} for a {@code float}.
666 *
667 * @param value
668 * the float to add to the {@code hashCode}
669 * @return {@code this} instance.
670 */
671 public HashCodeBuilder append(final float value) {
672 iTotal = iTotal * iConstant + Float.floatToIntBits(value);
673 return this;
674 }
675
676 /**
677 * Append a {@code hashCode} for a {@code float} array.
678 *
679 * @param array
680 * the array to add to the {@code hashCode}
681 * @return {@code this} instance.
682 */
683 public HashCodeBuilder append(final float[] array) {
684 if (array == null) {
685 iTotal = iTotal * iConstant;
686 } else {
687 for (final float element : array) {
688 append(element);
689 }
690 }
691 return this;
692 }
693
694 /**
695 * Append a {@code hashCode} for an {@code int}.
696 *
697 * @param value
698 * the int to add to the {@code hashCode}
699 * @return {@code this} instance.
700 */
701 public HashCodeBuilder append(final int value) {
702 iTotal = iTotal * iConstant + value;
703 return this;
704 }
705
706 /**
707 * Append a {@code hashCode} for an {@code int} array.
708 *
709 * @param array
710 * the array to add to the {@code hashCode}
711 * @return {@code this} instance.
712 */
713 public HashCodeBuilder append(final int[] array) {
714 if (array == null) {
715 iTotal = iTotal * iConstant;
716 } else {
717 for (final int element : array) {
718 append(element);
719 }
720 }
721 return this;
722 }
723
724 /**
725 * Append a {@code hashCode} for a {@code long}.
726 *
727 * @param value
728 * the long to add to the {@code hashCode}
729 * @return {@code this} instance.
730 */
731 // NOTE: This method uses >> and not >>> as Effective Java and
732 // Long.hashCode do. Ideally we should switch to >>> at
733 // some stage. There are backwards compat issues, so
734 // that will have to wait for the time being. cf LANG-342.
735 public HashCodeBuilder append(final long value) {
736 iTotal = iTotal * iConstant + (int) (value ^ value >> 32);
737 return this;
738 }
739
740 /**
741 * Append a {@code hashCode} for a {@code long} array.
742 *
743 * @param array
744 * the array to add to the {@code hashCode}
745 * @return {@code this} instance.
746 */
747 public HashCodeBuilder append(final long[] array) {
748 if (array == null) {
749 iTotal = iTotal * iConstant;
750 } else {
751 for (final long element : array) {
752 append(element);
753 }
754 }
755 return this;
756 }
757
758 /**
759 * Append a {@code hashCode} for an {@link Object}.
760 *
761 * @param object
762 * the Object to add to the {@code hashCode}
763 * @return {@code this} instance.
764 */
765 public HashCodeBuilder append(final Object object) {
766 if (object == null) {
767 iTotal = iTotal * iConstant;
768
769 } else if (ObjectUtils.isArray(object)) {
770 // factor out array case in order to keep method small enough
771 // to be inlined
772 appendArray(object);
773 } else {
774 iTotal = iTotal * iConstant + object.hashCode();
775 }
776 return this;
777 }
778
779 /**
780 * Append a {@code hashCode} for an {@link Object} array.
781 *
782 * @param array
783 * the array to add to the {@code hashCode}
784 * @return {@code this} instance.
785 */
786 public HashCodeBuilder append(final Object[] array) {
787 if (array == null) {
788 iTotal = iTotal * iConstant;
789 } else {
790 for (final Object element : array) {
791 append(element);
792 }
793 }
794 return this;
795 }
796
797 /**
798 * Append a {@code hashCode} for a {@code short}.
799 *
800 * @param value
801 * the short to add to the {@code hashCode}
802 * @return {@code this} instance.
803 */
804 public HashCodeBuilder append(final short value) {
805 iTotal = iTotal * iConstant + value;
806 return this;
807 }
808
809 /**
810 * Append a {@code hashCode} for a {@code short} array.
811 *
812 * @param array
813 * the array to add to the {@code hashCode}
814 * @return {@code this} instance.
815 */
816 public HashCodeBuilder append(final short[] array) {
817 if (array == null) {
818 iTotal = iTotal * iConstant;
819 } else {
820 for (final short element : array) {
821 append(element);
822 }
823 }
824 return this;
825 }
826
827 /**
828 * Append a {@code hashCode} for an array.
829 *
830 * @param object
831 * the array to add to the {@code hashCode}
832 */
833 private void appendArray(final Object object) {
834 // 'Switch' on type of array, to dispatch to the correct handler
835 // This handles multidimensional arrays
836 if (object instanceof long[]) {
837 append((long[]) object);
838 } else if (object instanceof int[]) {
839 append((int[]) object);
840 } else if (object instanceof short[]) {
841 append((short[]) object);
842 } else if (object instanceof char[]) {
843 append((char[]) object);
844 } else if (object instanceof byte[]) {
845 append((byte[]) object);
846 } else if (object instanceof double[]) {
847 append((double[]) object);
848 } else if (object instanceof float[]) {
849 append((float[]) object);
850 } else if (object instanceof boolean[]) {
851 append((boolean[]) object);
852 } else {
853 // Not an array of primitives
854 append((Object[]) object);
855 }
856 }
857
858 /**
859 * Adds the result of super.hashCode() to this builder.
860 *
861 * @param superHashCode
862 * the result of calling {@code super.hashCode()}
863 * @return {@code this} instance.
864 * @since 2.0
865 */
866 public HashCodeBuilder appendSuper(final int superHashCode) {
867 iTotal = iTotal * iConstant + superHashCode;
868 return this;
869 }
870
871 /**
872 * Returns the computed {@code hashCode}.
873 *
874 * @return {@code hashCode} based on the fields appended
875 * @since 3.0
876 */
877 @Override
878 public Integer build() {
879 return Integer.valueOf(toHashCode());
880 }
881
882 /**
883 * Implements equals using the hash code.
884 *
885 * @since 3.13.0
886 */
887 @Override
888 public boolean equals(final Object obj) {
889 if (this == obj) {
890 return true;
891 }
892 if (!(obj instanceof HashCodeBuilder)) {
893 return false;
894 }
895 final HashCodeBuilder other = (HashCodeBuilder) obj;
896 return iTotal == other.iTotal;
897 }
898
899 /**
900 * The computed {@code hashCode} from toHashCode() is returned due to the likelihood
901 * of bugs in mis-calling toHashCode() and the unlikeliness of it mattering what the hashCode for
902 * HashCodeBuilder itself is.
903 *
904 * @return {@code hashCode} based on the fields appended
905 * @since 2.5
906 */
907 @Override
908 public int hashCode() {
909 return toHashCode();
910 }
911
912 /**
913 * Returns the computed {@code hashCode}.
914 *
915 * @return {@code hashCode} based on the fields appended
916 */
917 public int toHashCode() {
918 return iTotal;
919 }
920
921 }