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