Coverage report

  %line %branch
org.apache.jetspeed.util.HashCodeBuilder
0% 
0% 

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

This report is generated by jcoverage, Maven and Maven JCoverage Plugin.