001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018 package org.apache.commons.lang.builder; 019 020 import java.lang.reflect.AccessibleObject; 021 import java.lang.reflect.Field; 022 import java.lang.reflect.Modifier; 023 import java.util.Collection; 024 import java.util.HashSet; 025 import java.util.Set; 026 027 import org.apache.commons.lang.ArrayUtils; 028 029 /** 030 * <p> 031 * Assists in implementing {@link Object#hashCode()} methods. 032 * </p> 033 * 034 * <p> 035 * This class enables a good <code>hashCode</code> method to be built for any class. It follows the rules laid out in 036 * the book <a href="http://java.sun.com/docs/books/effective/index.html">Effective Java</a> by Joshua Bloch. Writing a 037 * good <code>hashCode</code> method is actually quite difficult. This class aims to simplify the process. 038 * </p> 039 * 040 * <p> 041 * All relevant fields from the object should be included in the <code>hashCode</code> method. Derived fields may be 042 * excluded. In general, any field used in the <code>equals</code> method must be used in the <code>hashCode</code> 043 * method. 044 * </p> 045 * 046 * <p> 047 * To use this class write code as follows: 048 * </p> 049 * 050 * <pre> 051 * public class Person { 052 * String name; 053 * int age; 054 * boolean smoker; 055 * ... 056 * 057 * public int hashCode() { 058 * // you pick a hard-coded, randomly chosen, non-zero, odd number 059 * // ideally different for each class 060 * return new HashCodeBuilder(17, 37). 061 * append(name). 062 * append(age). 063 * append(smoker). 064 * toHashCode(); 065 * } 066 * } 067 * </pre> 068 * 069 * <p> 070 * If required, the superclass <code>hashCode()</code> can be added using {@link #appendSuper}. 071 * </p> 072 * 073 * <p> 074 * Alternatively, there is a method that uses reflection to determine the fields to test. Because these fields are 075 * usually private, the method, <code>reflectionHashCode</code>, uses <code>AccessibleObject.setAccessible</code> 076 * to change the visibility of the fields. This will fail under a security manager, unless the appropriate permissions 077 * are set up correctly. It is also slower than testing explicitly. 078 * </p> 079 * 080 * <p> 081 * A typical invocation for this method would look like: 082 * </p> 083 * 084 * <pre> 085 * public int hashCode() { 086 * return HashCodeBuilder.reflectionHashCode(this); 087 * } 088 * </pre> 089 * 090 * @author Apache Software Foundation 091 * @author Gary Gregory 092 * @author Pete Gieser 093 * @since 1.0 094 * @version $Id: HashCodeBuilder.java 907376 2010-02-07 03:43:02Z mbenson $ 095 */ 096 public class HashCodeBuilder { 097 /** 098 * <p> 099 * A registry of objects used by reflection methods to detect cyclical object references and avoid infinite loops. 100 * </p> 101 * 102 * @since 2.3 103 */ 104 private static final ThreadLocal REGISTRY = new ThreadLocal(); 105 106 /* 107 * N.B. we cannot store the actual objects in a HashSet, as that would use the very hashCode() 108 * we are in the process of calculating. 109 * 110 * So we generate a one-to-one mapping from the original object to a new object. 111 * 112 * Now HashSet uses equals() to determine if two elements with the same hashcode really 113 * are equal, so we also need to ensure that the replacement objects are only equal 114 * if the original objects are identical. 115 * 116 * The original implementation (2.4 and before) used the System.indentityHashCode() 117 * method - however this is not guaranteed to generate unique ids (e.g. LANG-459) 118 * 119 * We now use the IDKey helper class (adapted from org.apache.axis.utils.IDKey) 120 * to disambiguate the duplicate ids. 121 */ 122 123 /** 124 * <p> 125 * Returns the registry of objects being traversed by the reflection methods in the current thread. 126 * </p> 127 * 128 * @return Set the registry of objects being traversed 129 * @since 2.3 130 */ 131 static Set getRegistry() { 132 return (Set) REGISTRY.get(); 133 } 134 135 /** 136 * <p> 137 * Returns <code>true</code> if the registry contains the given object. Used by the reflection methods to avoid 138 * infinite loops. 139 * </p> 140 * 141 * @param value 142 * The object to lookup in the registry. 143 * @return boolean <code>true</code> if the registry contains the given object. 144 * @since 2.3 145 */ 146 static boolean isRegistered(Object value) { 147 Set registry = getRegistry(); 148 return registry != null && registry.contains(new IDKey(value)); 149 } 150 151 /** 152 * <p> 153 * Appends the fields and values defined by the given object of the given <code>Class</code>. 154 * </p> 155 * 156 * @param object 157 * the object to append details of 158 * @param clazz 159 * the class to append details of 160 * @param builder 161 * the builder to append to 162 * @param useTransients 163 * whether to use transient fields 164 * @param excludeFields 165 * Collection of String field names to exclude from use in calculation of hash code 166 */ 167 private static void reflectionAppend(Object object, Class clazz, HashCodeBuilder builder, boolean useTransients, 168 String[] excludeFields) { 169 if (isRegistered(object)) { 170 return; 171 } 172 try { 173 register(object); 174 Field[] fields = clazz.getDeclaredFields(); 175 AccessibleObject.setAccessible(fields, true); 176 for (int i = 0; i < fields.length; i++) { 177 Field field = fields[i]; 178 if (!ArrayUtils.contains(excludeFields, field.getName()) 179 && (field.getName().indexOf('$') == -1) 180 && (useTransients || !Modifier.isTransient(field.getModifiers())) 181 && (!Modifier.isStatic(field.getModifiers()))) { 182 try { 183 Object fieldValue = field.get(object); 184 builder.append(fieldValue); 185 } catch (IllegalAccessException e) { 186 // this can't happen. Would get a Security exception instead 187 // throw a runtime exception in case the impossible happens. 188 throw new InternalError("Unexpected IllegalAccessException"); 189 } 190 } 191 } 192 } finally { 193 unregister(object); 194 } 195 } 196 197 /** 198 * <p> 199 * This method uses reflection to build a valid hash code. 200 * </p> 201 * 202 * <p> 203 * It uses <code>AccessibleObject.setAccessible</code> to gain access to private fields. This means that it will 204 * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is 205 * also not as efficient as testing explicitly. 206 * </p> 207 * 208 * <p> 209 * Transient members will be not be used, as they are likely derived fields, and not part of the value of the 210 * <code>Object</code>. 211 * </p> 212 * 213 * <p> 214 * Static fields will not be tested. Superclass fields will be included. 215 * </p> 216 * 217 * <p> 218 * Two randomly chosen, non-zero, odd numbers must be passed in. Ideally these should be different for each class, 219 * however this is not vital. Prime numbers are preferred, especially for the multiplier. 220 * </p> 221 * 222 * @param initialNonZeroOddNumber 223 * a non-zero, odd number used as the initial value 224 * @param multiplierNonZeroOddNumber 225 * a non-zero, odd number used as the multiplier 226 * @param object 227 * the Object to create a <code>hashCode</code> for 228 * @return int hash code 229 * @throws IllegalArgumentException 230 * if the Object is <code>null</code> 231 * @throws IllegalArgumentException 232 * if the number is zero or even 233 */ 234 public static int reflectionHashCode(int initialNonZeroOddNumber, int multiplierNonZeroOddNumber, Object object) { 235 return reflectionHashCode(initialNonZeroOddNumber, multiplierNonZeroOddNumber, object, false, null, null); 236 } 237 238 /** 239 * <p> 240 * This method uses reflection to build a valid hash code. 241 * </p> 242 * 243 * <p> 244 * It uses <code>AccessibleObject.setAccessible</code> to gain access to private fields. This means that it will 245 * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is 246 * also not as efficient as testing explicitly. 247 * </p> 248 * 249 * <p> 250 * If the TestTransients parameter is set to <code>true</code>, transient members will be tested, otherwise they 251 * are ignored, as they are likely derived fields, and not part of the value of the <code>Object</code>. 252 * </p> 253 * 254 * <p> 255 * Static fields will not be tested. Superclass fields will be included. 256 * </p> 257 * 258 * <p> 259 * Two randomly chosen, non-zero, odd numbers must be passed in. Ideally these should be different for each class, 260 * however this is not vital. 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, int multiplierNonZeroOddNumber, Object object, 278 boolean testTransients) { 279 return reflectionHashCode(initialNonZeroOddNumber, multiplierNonZeroOddNumber, object, testTransients, null, 280 null); 281 } 282 283 /** 284 * Calls {@link #reflectionHashCode(int, int, Object, boolean, Class, String[])} with excludeFields set to 285 * <code>null</code>. 286 * 287 * @param initialNonZeroOddNumber 288 * a non-zero, odd number used as the initial value 289 * @param multiplierNonZeroOddNumber 290 * a non-zero, odd number used as the multiplier 291 * @param object 292 * the Object to create a <code>hashCode</code> for 293 * @param testTransients 294 * whether to include transient fields 295 * @param reflectUpToClass 296 * the superclass to reflect up to (inclusive), may be <code>null</code> 297 * @return int hash code 298 */ 299 public static int reflectionHashCode(int initialNonZeroOddNumber, int multiplierNonZeroOddNumber, Object object, 300 boolean testTransients, Class reflectUpToClass) { 301 return reflectionHashCode(initialNonZeroOddNumber, multiplierNonZeroOddNumber, object, testTransients, 302 reflectUpToClass, null); 303 } 304 305 /** 306 * <p> 307 * This method uses reflection to build a valid hash code. 308 * </p> 309 * 310 * <p> 311 * It uses <code>AccessibleObject.setAccessible</code> to gain access to private fields. This means that it will 312 * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is 313 * also not as efficient as testing explicitly. 314 * </p> 315 * 316 * <p> 317 * If the TestTransients parameter is set to <code>true</code>, transient members will be tested, otherwise they 318 * are ignored, as they are likely derived fields, and not part of the value of the <code>Object</code>. 319 * </p> 320 * 321 * <p> 322 * Static fields will not be included. Superclass fields will be included up to and including the specified 323 * superclass. A null superclass is treated as java.lang.Object. 324 * </p> 325 * 326 * <p> 327 * Two randomly chosen, non-zero, odd numbers must be passed in. Ideally these should be different for each class, 328 * however this is not vital. Prime numbers are preferred, especially for the multiplier. 329 * </p> 330 * 331 * @param initialNonZeroOddNumber 332 * a non-zero, odd number used as the initial value 333 * @param multiplierNonZeroOddNumber 334 * a non-zero, odd number used as the multiplier 335 * @param object 336 * the Object to create a <code>hashCode</code> for 337 * @param testTransients 338 * whether to include transient fields 339 * @param reflectUpToClass 340 * the superclass to reflect up to (inclusive), may be <code>null</code> 341 * @param excludeFields 342 * array of field names to exclude from use in calculation of hash code 343 * @return int hash code 344 * @throws IllegalArgumentException 345 * if the Object is <code>null</code> 346 * @throws IllegalArgumentException 347 * if the number is zero or even 348 * @since 2.0 349 */ 350 public static int reflectionHashCode(int initialNonZeroOddNumber, int multiplierNonZeroOddNumber, Object object, 351 boolean testTransients, Class reflectUpToClass, String[] excludeFields) { 352 353 if (object == null) { 354 throw new IllegalArgumentException("The object to build a hash code for must not be null"); 355 } 356 HashCodeBuilder builder = new HashCodeBuilder(initialNonZeroOddNumber, multiplierNonZeroOddNumber); 357 Class clazz = object.getClass(); 358 reflectionAppend(object, clazz, builder, testTransients, excludeFields); 359 while (clazz.getSuperclass() != null && clazz != reflectUpToClass) { 360 clazz = clazz.getSuperclass(); 361 reflectionAppend(object, clazz, builder, testTransients, excludeFields); 362 } 363 return builder.toHashCode(); 364 } 365 366 /** 367 * <p> 368 * This method uses reflection to build a valid hash code. 369 * </p> 370 * 371 * <p> 372 * This constructor uses two hard coded choices for the constants needed to build a hash code. 373 * </p> 374 * 375 * <p> 376 * It uses <code>AccessibleObject.setAccessible</code> to gain access to private fields. This means that it will 377 * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is 378 * also not as efficient as testing explicitly. 379 * </p> 380 * 381 * <p> 382 * Transient members will be not be used, as they are likely derived fields, and not part of the value of the 383 * <code>Object</code>. 384 * </p> 385 * 386 * <p> 387 * Static fields will not be tested. Superclass fields will be included. 388 * </p> 389 * 390 * @param object 391 * the Object to create a <code>hashCode</code> for 392 * @return int hash code 393 * @throws IllegalArgumentException 394 * if the object is <code>null</code> 395 */ 396 public static int reflectionHashCode(Object object) { 397 return reflectionHashCode(17, 37, object, false, null, null); 398 } 399 400 /** 401 * <p> 402 * This method uses reflection to build a valid hash code. 403 * </p> 404 * 405 * <p> 406 * This constructor uses two hard coded choices for the constants needed to build a hash code. 407 * </p> 408 * 409 * <p> 410 * It uses <code>AccessibleObject.setAccessible</code> to gain access to private fields. This means that it will 411 * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is 412 * also not as efficient as testing explicitly. 413 * </p> 414 * 415 * <P> 416 * If the TestTransients parameter is set to <code>true</code>, transient members will be tested, otherwise they 417 * are ignored, as they are likely derived fields, and not part of the value of the <code>Object</code>. 418 * </p> 419 * 420 * <p> 421 * Static fields will not be tested. Superclass fields will be included. 422 * </p> 423 * 424 * @param object 425 * the Object to create a <code>hashCode</code> for 426 * @param testTransients 427 * whether to include transient fields 428 * @return int hash code 429 * @throws IllegalArgumentException 430 * if the object is <code>null</code> 431 */ 432 public static int reflectionHashCode(Object object, boolean testTransients) { 433 return reflectionHashCode(17, 37, object, testTransients, null, null); 434 } 435 436 /** 437 * <p> 438 * This method uses reflection to build a valid hash code. 439 * </p> 440 * 441 * <p> 442 * This constructor uses two hard coded choices for the constants needed to build a hash code. 443 * </p> 444 * 445 * <p> 446 * It uses <code>AccessibleObject.setAccessible</code> to gain access to private fields. This means that it will 447 * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is 448 * also not as efficient as testing explicitly. 449 * </p> 450 * 451 * <p> 452 * Transient members will be not be used, as they are likely derived fields, and not part of the value of the 453 * <code>Object</code>. 454 * </p> 455 * 456 * <p> 457 * Static fields will not be tested. Superclass fields will be included. 458 * </p> 459 * 460 * @param object 461 * the Object to create a <code>hashCode</code> for 462 * @param excludeFields 463 * Collection of String field names to exclude from use in calculation of hash code 464 * @return int hash code 465 * @throws IllegalArgumentException 466 * if the object is <code>null</code> 467 */ 468 public static int reflectionHashCode(Object object, Collection /* String */excludeFields) { 469 return reflectionHashCode(object, ReflectionToStringBuilder.toNoNullStringArray(excludeFields)); 470 } 471 472 // ------------------------------------------------------------------------- 473 474 /** 475 * <p> 476 * This method uses reflection to build a valid hash code. 477 * </p> 478 * 479 * <p> 480 * This constructor uses two hard coded choices for the constants needed to build a hash code. 481 * </p> 482 * 483 * <p> 484 * It uses <code>AccessibleObject.setAccessible</code> to gain access to private fields. This means that it will 485 * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is 486 * also not as efficient as testing explicitly. 487 * </p> 488 * 489 * <p> 490 * Transient members will be not be used, as they are likely derived fields, and not part of the value of the 491 * <code>Object</code>. 492 * </p> 493 * 494 * <p> 495 * Static fields will not be tested. Superclass fields will be included. 496 * </p> 497 * 498 * @param object 499 * the Object to create a <code>hashCode</code> for 500 * @param excludeFields 501 * array of field names to exclude from use in calculation of hash code 502 * @return int hash code 503 * @throws IllegalArgumentException 504 * if the object is <code>null</code> 505 */ 506 public static int reflectionHashCode(Object object, String[] excludeFields) { 507 return reflectionHashCode(17, 37, object, false, null, excludeFields); 508 } 509 510 /** 511 * <p> 512 * Registers the given object. Used by the reflection methods to avoid infinite loops. 513 * </p> 514 * 515 * @param value 516 * The object to register. 517 */ 518 static void register(Object value) { 519 synchronized (HashCodeBuilder.class) { 520 if (getRegistry() == null) { 521 REGISTRY.set(new HashSet()); 522 } 523 } 524 getRegistry().add(new IDKey(value)); 525 } 526 527 /** 528 * <p> 529 * Unregisters the given object. 530 * </p> 531 * 532 * <p> 533 * Used by the reflection methods to avoid infinite loops. 534 * 535 * @param value 536 * The object to unregister. 537 * @since 2.3 538 */ 539 static void unregister(Object value) { 540 Set registry = getRegistry(); 541 if (registry != null) { 542 registry.remove(new IDKey(value)); 543 synchronized (HashCodeBuilder.class) { 544 //read again 545 registry = getRegistry(); 546 if (registry != null && registry.isEmpty()) { 547 REGISTRY.set(null); 548 } 549 } 550 } 551 } 552 553 /** 554 * Constant to use in building the hashCode. 555 */ 556 private final int iConstant; 557 558 /** 559 * Running total of the hashCode. 560 */ 561 private int iTotal = 0; 562 563 /** 564 * <p> 565 * Uses two hard coded choices for the constants needed to build a <code>hashCode</code>. 566 * </p> 567 */ 568 public HashCodeBuilder() { 569 iConstant = 37; 570 iTotal = 17; 571 } 572 573 /** 574 * <p> 575 * Two randomly chosen, non-zero, odd numbers must be passed in. Ideally these should be different for each class, 576 * however this is not vital. 577 * </p> 578 * 579 * <p> 580 * Prime numbers are preferred, especially for the multiplier. 581 * </p> 582 * 583 * @param initialNonZeroOddNumber 584 * a non-zero, odd number used as the initial value 585 * @param multiplierNonZeroOddNumber 586 * a non-zero, odd number used as the multiplier 587 * @throws IllegalArgumentException 588 * if the number is zero or even 589 */ 590 public HashCodeBuilder(int initialNonZeroOddNumber, int multiplierNonZeroOddNumber) { 591 if (initialNonZeroOddNumber == 0) { 592 throw new IllegalArgumentException("HashCodeBuilder requires a non zero initial value"); 593 } 594 if (initialNonZeroOddNumber % 2 == 0) { 595 throw new IllegalArgumentException("HashCodeBuilder requires an odd initial value"); 596 } 597 if (multiplierNonZeroOddNumber == 0) { 598 throw new IllegalArgumentException("HashCodeBuilder requires a non zero multiplier"); 599 } 600 if (multiplierNonZeroOddNumber % 2 == 0) { 601 throw new IllegalArgumentException("HashCodeBuilder requires an odd multiplier"); 602 } 603 iConstant = multiplierNonZeroOddNumber; 604 iTotal = initialNonZeroOddNumber; 605 } 606 607 /** 608 * <p> 609 * Append a <code>hashCode</code> for a <code>boolean</code>. 610 * </p> 611 * <p> 612 * This adds <code>iConstant * 1</code> to the <code>hashCode</code> and not a <code>1231</code> or 613 * <code>1237</code> as done in java.lang.Boolean. This is in accordance with the <quote>Effective Java</quote> 614 * design. 615 * </p> 616 * 617 * @param value 618 * the boolean to add to the <code>hashCode</code> 619 * @return this 620 */ 621 public HashCodeBuilder append(boolean value) { 622 iTotal = iTotal * iConstant + (value ? 0 : 1); 623 return this; 624 } 625 626 /** 627 * <p> 628 * Append a <code>hashCode</code> for a <code>boolean</code> array. 629 * </p> 630 * 631 * @param array 632 * the array to add to the <code>hashCode</code> 633 * @return this 634 */ 635 public HashCodeBuilder append(boolean[] array) { 636 if (array == null) { 637 iTotal = iTotal * iConstant; 638 } else { 639 for (int i = 0; i < array.length; i++) { 640 append(array[i]); 641 } 642 } 643 return this; 644 } 645 646 // ------------------------------------------------------------------------- 647 648 /** 649 * <p> 650 * Append a <code>hashCode</code> for a <code>byte</code>. 651 * </p> 652 * 653 * @param value 654 * the byte to add to the <code>hashCode</code> 655 * @return this 656 */ 657 public HashCodeBuilder append(byte value) { 658 iTotal = iTotal * iConstant + value; 659 return this; 660 } 661 662 // ------------------------------------------------------------------------- 663 664 /** 665 * <p> 666 * Append a <code>hashCode</code> for a <code>byte</code> array. 667 * </p> 668 * 669 * @param array 670 * the array to add to the <code>hashCode</code> 671 * @return this 672 */ 673 public HashCodeBuilder append(byte[] 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> 686 * Append a <code>hashCode</code> for a <code>char</code>. 687 * </p> 688 * 689 * @param value 690 * the char to add to the <code>hashCode</code> 691 * @return this 692 */ 693 public HashCodeBuilder append(char value) { 694 iTotal = iTotal * iConstant + value; 695 return this; 696 } 697 698 /** 699 * <p> 700 * Append a <code>hashCode</code> for a <code>char</code> array. 701 * </p> 702 * 703 * @param array 704 * the array to add to the <code>hashCode</code> 705 * @return this 706 */ 707 public HashCodeBuilder append(char[] array) { 708 if (array == null) { 709 iTotal = iTotal * iConstant; 710 } else { 711 for (int i = 0; i < array.length; i++) { 712 append(array[i]); 713 } 714 } 715 return this; 716 } 717 718 /** 719 * <p> 720 * Append a <code>hashCode</code> for a <code>double</code>. 721 * </p> 722 * 723 * @param value 724 * the double to add to the <code>hashCode</code> 725 * @return this 726 */ 727 public HashCodeBuilder append(double value) { 728 return append(Double.doubleToLongBits(value)); 729 } 730 731 /** 732 * <p> 733 * Append a <code>hashCode</code> for a <code>double</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(double[] 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>float</code>. 754 * </p> 755 * 756 * @param value 757 * the float to add to the <code>hashCode</code> 758 * @return this 759 */ 760 public HashCodeBuilder append(float value) { 761 iTotal = iTotal * iConstant + Float.floatToIntBits(value); 762 return this; 763 } 764 765 /** 766 * <p> 767 * Append a <code>hashCode</code> for a <code>float</code> array. 768 * </p> 769 * 770 * @param array 771 * the array to add to the <code>hashCode</code> 772 * @return this 773 */ 774 public HashCodeBuilder append(float[] array) { 775 if (array == null) { 776 iTotal = iTotal * iConstant; 777 } else { 778 for (int i = 0; i < array.length; i++) { 779 append(array[i]); 780 } 781 } 782 return this; 783 } 784 785 /** 786 * <p> 787 * Append a <code>hashCode</code> for an <code>int</code>. 788 * </p> 789 * 790 * @param value 791 * the int to add to the <code>hashCode</code> 792 * @return this 793 */ 794 public HashCodeBuilder append(int value) { 795 iTotal = iTotal * iConstant + value; 796 return this; 797 } 798 799 /** 800 * <p> 801 * Append a <code>hashCode</code> for an <code>int</code> array. 802 * </p> 803 * 804 * @param array 805 * the array to add to the <code>hashCode</code> 806 * @return this 807 */ 808 public HashCodeBuilder append(int[] array) { 809 if (array == null) { 810 iTotal = iTotal * iConstant; 811 } else { 812 for (int i = 0; i < array.length; i++) { 813 append(array[i]); 814 } 815 } 816 return this; 817 } 818 819 /** 820 * <p> 821 * Append a <code>hashCode</code> for a <code>long</code>. 822 * </p> 823 * 824 * @param value 825 * the long to add to the <code>hashCode</code> 826 * @return this 827 */ 828 // NOTE: This method uses >> and not >>> as Effective Java and 829 // Long.hashCode do. Ideally we should switch to >>> at 830 // some stage. There are backwards compat issues, so 831 // that will have to wait for the time being. cf LANG-342. 832 public HashCodeBuilder append(long value) { 833 iTotal = iTotal * iConstant + ((int) (value ^ (value >> 32))); 834 return this; 835 } 836 837 /** 838 * <p> 839 * Append a <code>hashCode</code> for a <code>long</code> array. 840 * </p> 841 * 842 * @param array 843 * the array to add to the <code>hashCode</code> 844 * @return this 845 */ 846 public HashCodeBuilder append(long[] array) { 847 if (array == null) { 848 iTotal = iTotal * iConstant; 849 } else { 850 for (int i = 0; i < array.length; i++) { 851 append(array[i]); 852 } 853 } 854 return this; 855 } 856 857 /** 858 * <p> 859 * Append a <code>hashCode</code> for an <code>Object</code>. 860 * </p> 861 * 862 * @param object 863 * the Object to add to the <code>hashCode</code> 864 * @return this 865 */ 866 public HashCodeBuilder append(Object object) { 867 if (object == null) { 868 iTotal = iTotal * iConstant; 869 870 } else { 871 if(object.getClass().isArray()) { 872 // 'Switch' on type of array, to dispatch to the correct handler 873 // This handles multi dimensional arrays 874 if (object instanceof long[]) { 875 append((long[]) object); 876 } else if (object instanceof int[]) { 877 append((int[]) object); 878 } else if (object instanceof short[]) { 879 append((short[]) object); 880 } else if (object instanceof char[]) { 881 append((char[]) object); 882 } else if (object instanceof byte[]) { 883 append((byte[]) object); 884 } else if (object instanceof double[]) { 885 append((double[]) object); 886 } else if (object instanceof float[]) { 887 append((float[]) object); 888 } else if (object instanceof boolean[]) { 889 append((boolean[]) object); 890 } else { 891 // Not an array of primitives 892 append((Object[]) object); 893 } 894 } else { 895 iTotal = iTotal * iConstant + object.hashCode(); 896 } 897 } 898 return this; 899 } 900 901 /** 902 * <p> 903 * Append a <code>hashCode</code> for an <code>Object</code> array. 904 * </p> 905 * 906 * @param array 907 * the array to add to the <code>hashCode</code> 908 * @return this 909 */ 910 public HashCodeBuilder append(Object[] array) { 911 if (array == null) { 912 iTotal = iTotal * iConstant; 913 } else { 914 for (int i = 0; i < array.length; i++) { 915 append(array[i]); 916 } 917 } 918 return this; 919 } 920 921 /** 922 * <p> 923 * Append a <code>hashCode</code> for a <code>short</code>. 924 * </p> 925 * 926 * @param value 927 * the short to add to the <code>hashCode</code> 928 * @return this 929 */ 930 public HashCodeBuilder append(short value) { 931 iTotal = iTotal * iConstant + value; 932 return this; 933 } 934 935 /** 936 * <p> 937 * Append a <code>hashCode</code> for a <code>short</code> array. 938 * </p> 939 * 940 * @param array 941 * the array to add to the <code>hashCode</code> 942 * @return this 943 */ 944 public HashCodeBuilder append(short[] array) { 945 if (array == null) { 946 iTotal = iTotal * iConstant; 947 } else { 948 for (int i = 0; i < array.length; i++) { 949 append(array[i]); 950 } 951 } 952 return this; 953 } 954 955 /** 956 * <p> 957 * Adds the result of super.hashCode() to this builder. 958 * </p> 959 * 960 * @param superHashCode 961 * the result of calling <code>super.hashCode()</code> 962 * @return this HashCodeBuilder, used to chain calls. 963 * @since 2.0 964 */ 965 public HashCodeBuilder appendSuper(int superHashCode) { 966 iTotal = iTotal * iConstant + superHashCode; 967 return this; 968 } 969 970 /** 971 * <p> 972 * Return the computed <code>hashCode</code>. 973 * </p> 974 * 975 * @return <code>hashCode</code> based on the fields appended 976 */ 977 public int toHashCode() { 978 return iTotal; 979 } 980 981 /** 982 * <p> 983 * The computed <code>hashCode</code> from toHashCode() is returned due to the likelyhood 984 * of bugs in mis-calling toHashCode() and the unlikelyness of it mattering what the hashCode for 985 * HashCodeBuilder itself is. 986 * 987 * @return <code>hashCode</code> based on the fields appended 988 * @since 2.5 989 */ 990 public int hashCode() { 991 return toHashCode(); 992 } 993 994 }