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