View Javadoc

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