All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.squeakysand.commons.lang.HashCodeHelper Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2010-2012 Craig S. Dickson (http://craigsdickson.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.squeakysand.commons.lang;

import java.util.Collection;
import java.util.Map;

import com.squeakysand.commons.beans.BeanHelper;
import com.squeakysand.commons.beans.BeanHelperException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Helper class for writing good hashCode() methods. All hash methods that accept an array as a parameter
 * and the hash method that accepts a single Object parameter safely handle a null value being passed as
 * the argument to the method - methods that accept an array also safely handle a null element in the
 * array.
 */
public final class HashCodeHelper {

    private static final int MULTIPLIER = 37;
    private static final int SEED = 17;
    private static final Logger LOG = LoggerFactory.getLogger(EqualsHelper.class);

    private HashCodeHelper() {
    }

    /**
     * Generates a hash value for the passed in argument by extracting the readable JavaBean properties of the object and hashing those values and combining the
     * results. This method can be used to help implement the 
     * hashCode method of an object that adheres to the JavaBean pattern. However, while this method will generate a good hash value, it is written in a
     * generic manner and it may be possible to write a more specific and efficient hashing algorithm for specific classes if performance becomes an issue.
     *
     * @param bean
     *            the JavaBean to generate a hash value for.
     * @return a hash value based on the readable properties of the JavaBean.
     */
    public static int hashAsJavaBean(Object bean) {
        int result = 0;
        try {
            Map propertyMap = BeanHelper.getPropertyValues(bean, true);
            Collection propertyValues = propertyMap.values();
            for (Object propertyValue : propertyValues) {
                result += hashCode(propertyValue);
            }
        } catch (BeanHelperException e) {
            // log the error and just return the value of result as it is
            LOG.error(e.getMessage(), e);
        }
        return result;
    }

    public static int hashAsJavaBean(Object bean, String... propertyNameFilter) {
        int result = 0;
        try {
            Map propertyMap = BeanHelper.getPropertyValues(bean, true, propertyNameFilter);
            Collection propertyValues = propertyMap.values();
            for (Object propertyValue : propertyValues) {
                result += hashCode(propertyValue);
            }
        } catch (BeanHelperException e) {
            // log the error and just return the value of result as it is
            LOG.error(e.getMessage(), e);
        }
        return result;
    }

    /**
     * Generates hash value for a single boolean.
     *
     * @param   b  the boolean to hash.
     * @return  the resulting hash value.
     */
    public static int hashCode(boolean b) {
        int result = 0;
        if (b) {
            result = 1;
        }
        return result;
    }

    /**
     * Generates a hash value for an array of booleans.
     *
     * @param   b  the array to hash.
     * @return  the result of hashing each element and combining the results.
     */
    public static int hashCode(boolean[] b) {
        int result = 0;
        if (b != null) {
            result = SEED;
            for (int i = 0; i < b.length; i++) {
                result = (MULTIPLIER * result) + hashCode(b[i]);
            }
        }
        return result;
    }

    /**
     * Generates hash value for a single long.
     *
     * @param   l  the long to hash.
     * @return  the resulting hash value.
     */
    public static int hashCode(long l) {
        return (int) (l ^ (l >>> 32));
    }

    /**
     * Generates a hash value for an array of longs.
     *
     * @param   l  the array to hash.
     * @return  the result of hashing each element and combining the results.
     */
    public static int hashCode(long[] l) {
        int result = 0;
        if (l != null) {
            result = SEED;
            for (int i = 0; i < l.length; i++) {
                result = (MULTIPLIER * result) + hashCode(l[i]);
            }
        }
        return result;
    }

    /**
     * Generates hash value for a single float.
     *
     * @param   f  the float to hash.
     * @return  the resulting hash value.
     */
    public static int hashCode(float f) {
        return Float.floatToIntBits(f);
    }

    /**
     * Generates a hash value for an array of floats.
     *
     * @param   f  the array to hash.
     * @return  the result of hashing each element and combining the results.
     */
    public static int hashCode(float[] f) {
        int result = 0;
        if (f != null) {
            result = SEED;
            for (int i = 0; i < f.length; i++) {
                result = (MULTIPLIER * result) + hashCode(f[i]);
            }
        }
        return result;
    }

    /**
     * Generates hash value for a single double.
     *
     * @param   d  the double to hash.
     * @return  the resulting hash value.
     */
    public static int hashCode(double d) {
        return hashCode(Double.doubleToLongBits(d));
    }

    /**
     * Generates a hash value for an array of doubles.
     *
     * @param   d  the array to hash.
     * @return  the result of hashing each element and combining the results.
     */
    public static int hashCode(double[] d) {
        int result = 0;
        if (d != null) {
            result = SEED;
            for (int i = 0; i < d.length; i++) {
                result = (MULTIPLIER * result) + hashCode(d[i]);
            }
        }
        return result;
    }

    /**
     * Generates hash value for a single int, byte, char or short.
     *
     * @param   i  the int, byte, char or short to hash.
     * @return  the resulting hash value.
     */
    public static int hashCode(int i) {
        return i;
    }

    /**
     * Generates a hash value for an array of ints.
     *
     * @param   i  the array to hash.
     * @return  the result of hashing each element and combining the results.
     */
    public static int hashCode(int[] i) {
        int result = 0;
        if (i != null) {
            result = SEED;
            for (int j = 0; j < i.length; j++) {
                result = (MULTIPLIER * result) + hashCode(i[j]);
            }
        }
        return result;
    }

    /**
     * Generates a hash value for an array of bytes.
     *
     * @param   b  the array to hash.
     * @return  the result of hashing each element and combining the results.
     */
    public static int hashCode(byte[] b) {
        int result = 0;
        if (b != null) {
            result = SEED;
            for (int i = 0; i < b.length; i++) {
                result = (MULTIPLIER * result) + hashCode(b[i]);
            }
        }
        return result;
    }

    /**
     * Generates a hash value for an array of chars.
     *
     * @param   c  the array to hash.
     * @return  the result of hashing each element and combining the results.
     */
    public static int hashCode(char[] c) {
        int result = 0;
        if (c != null) {
            result = SEED;
            for (int i = 0; i < c.length; i++) {
                result = (MULTIPLIER * result) + hashCode(c[i]);
            }
        }
        return result;
    }

    /**
     * Generates a hash value for an array of shorts.
     *
     * @param   s  the array to hash.
     * @return  the result of hashing each element and combining the results.
     */
    public static int hashCode(short[] s) {
        int result = 0;
        if (s != null) {
            result = SEED;
            for (int i = 0; i < s.length; i++) {
                result = (MULTIPLIER * result) + hashCode(s[i]);
            }
        }
        return result;
    }

    /**
     * Generates hash value for a single non-primitive Object.
     *
     * 

WARNING : If the object passed to this method is a non-null value, it will simply return the result of * calling o.hashCode(). This will cause an infinite recursion loop to be created if o * uses this class to implement it's hashCode method.

* * @param o the Object to hash. * @return the resulting hash value. */ public static int hashCode(Object o) { int result = 0; if (o != null) { result = o.hashCode(); } return result; } /** * Generates a hash value for an array of Objects. * * @param o the array to hash. * @return the result of hashing each element and combining the results. */ public static int hashCode(Object[] o) { int result = 0; if (o != null) { result = SEED; for (int i = 0; i < o.length; i++) { result = (MULTIPLIER * result) + hashCode(o[i]); } } return result; } }