`
elicer
  • 浏览: 131560 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

AOP Cache的 HashCode cachekey 实现

阅读更多
AOP的cache  大家都很熟悉,关于cachekey的生成方式有多种,最简单的是className+methodName+parameters ,这种方法的弊端太多,如果parameter是一个复合对像,那么在拼key时就比较麻烦。
我在以前的一片文章中讲过用annotation来标注复合对象中需要作为cache的子对象,能解决复合对象generate cachekey的问题,但这是一种侵入式的,需要加入额外的代码,真正的AOP cache应该式非侵入式的,就是cache的生效不需要其它代码有任何额外的工作。做function的程序员不需要关心cache的任何东西,cache对他们来说是透明的。
所以这里我想到了一种用HashCode来作为AOP cache的实现。这样不管参数的类型是什么,对于我generate cachekey 都没有影响。
具体实现类:

Key generate Interface

import java.io.Serializable;

import org.aopalliance.intercept.MethodInvocation;

/**
 * <p>
 * Generates a unique key based on the description of an invocation to an
 * intercepted method.
 * </p>
 * 
 * @author Elicer Zheng
 */
public interface CacheKeyGenerator {

  /**
   * Generates the key for a cache entry.
   * 
   * @param methodInvocation
   *          the description of an invocation to the intercepted method.
   * @return the created key.
   */
  Serializable generateKey(MethodInvocation methodInvocation);
}





CacheGenerate 实现类

import java.io.Serializable;
import java.lang.reflect.Method;

import org.aopalliance.intercept.MethodInvocation;



/**
 * <p>
 * Generates the key for a cache entry using the hashCode of the intercepted
 * method and its arguments.
 * </p>
 * 
 * @author Elicer Zheng
 */
public class HashCodeCacheKeyGenerator implements CacheKeyGenerator {

  /**
   * Flag that indicates if this generator should generate the hash code of the
   * arguments passed to the method to apply caching to. If <code>false</code>,
   * this generator uses the default hash code of the arguments.
   */
  private boolean generateArgumentHashCode;

  /**
   * Construct a <code>HashCodeCacheKeyGenerator</code>.
   */
  public HashCodeCacheKeyGenerator() {
    super();
  }

  /**
   * Construct a <code>HashCodeCacheKeyGenerator</code>.
   * 
   * @param generateArgumentHashCode
   *          the new value for the flag that indicates if this generator should
   *          generate the hash code of the arguments passed to the method to
   *          apply caching to. If <code>false</code>, this generator uses
   *          the default hash code of the arguments.
   */
  public HashCodeCacheKeyGenerator(boolean generateArgumentHashCode) {
    this();
    setGenerateArgumentHashCode(generateArgumentHashCode);
  }

  /**
   * @see CacheKeyGenerator#generateKey(MethodInvocation)
   */
  public final Serializable generateKey(MethodInvocation methodInvocation) {
    HashCodeCalculator hashCodeCalculator = new HashCodeCalculator();

    Method method = methodInvocation.getMethod();
    hashCodeCalculator.append(System.identityHashCode(method));

    Object[] methodArguments = methodInvocation.getArguments();
    if (methodArguments != null) {
      int methodArgumentCount = methodArguments.length;

      for (int i = 0; i < methodArgumentCount; i++) {
        Object methodArgument = methodArguments[i];
        int hash = 0;

        if (generateArgumentHashCode) {
          hash = ReflectionsUtility.reflectionHashCode(methodArgument);
        } else {
          hash = ObjectsUtility.nullSafeHashCode(methodArgument);
        }

        hashCodeCalculator.append(hash);
      }
    }

    long checkSum = hashCodeCalculator.getCheckSum();
    int hashCode = hashCodeCalculator.getHashCode();

    Serializable cacheKey = new HashCodeCacheKey(checkSum, hashCode);
    return cacheKey;
  }

  /**
   * Sets the flag that indicates if this generator should generate the hash
   * code of the arguments passed to the method to apply caching to. If
   * <code>false</code>, this generator uses the default hash code of the
   * arguments.
   * 
   * @param newGenerateArgumentHashCode
   *          the new value of the flag
   */
  public final void setGenerateArgumentHashCode(
      boolean newGenerateArgumentHashCode) {
    generateArgumentHashCode = newGenerateArgumentHashCode;
  }

}


import java.io.Serializable;

/**
 * <p>
 * Cache key which value is based on a pre-calculated hash code.
 * </p>
 * 
 * @author Elicer Zheng
 */
public final class HashCodeCacheKey implements Serializable {

  private static final long serialVersionUID = 3904677167731454262L;

  /**
   * Number that helps keep the uniqueness of this key.
   */
  private long checkSum;

  /**
   * Pre-calculated hash code.
   */
  private int hashCode;

  /**
   * Construct a <code>HashCodeCacheKey</code>.
   */
  public HashCodeCacheKey() {
    super();
  }

  /**
   * Construct a <code>HashCodeCacheKey</code>.
   * 
   * @param newCheckSum
   *          the number that helps keep the uniqueness of this key
   * @param newHashCode
   *          the pre-calculated hash code
   */
  public HashCodeCacheKey(long newCheckSum, int newHashCode) {
    this();
    setCheckSum(newCheckSum);
    setHashCode(newHashCode);
  }

  /**
   * @see Object#equals(Object)
   */
  public boolean equals(Object obj) {
    if (this == obj) return true;
    if (!(obj instanceof HashCodeCacheKey)) return false;

    HashCodeCacheKey other = (HashCodeCacheKey) obj;
    if (checkSum != other.checkSum) return false;
    if (hashCode != other.hashCode) return false;

    return true;
  }

  /**
   * @return the number that helps keep the uniqueness of this key
   */
  public long getCheckSum() {
    return checkSum;
  }

  /**
   * @return the pre-calculated hash code
   */
  public int getHashCode() {
    return hashCode;
  }

  /**
   * @see Object#hashCode()
   */
  public int hashCode() {
    return getHashCode();
  }

  /**
   * Sets the number that helps keep the uniqueness of this key.
   * 
   * @param newCheckSum
   *          the new number
   */
  public void setCheckSum(long newCheckSum) {
    checkSum = newCheckSum;
  }

  /**
   * Sets the pre-calculated hash code.
   * 
   * @param newHashCode
   *          the new hash code
   */
  public void setHashCode(int newHashCode) {
    hashCode = newHashCode;
  }

  /**
   * @see Object#toString()
   */
  public String toString() {
    return getHashCode() + "|" + getCheckSum();
  }
}


/**
 *
 *This class is a HashCode Calculator
 * 
 * @author Elicer Zheng
 */
public final class HashCodeCalculator {

  private static final int INITIAL_HASH = 17;

  private static final int MULTIPLIER = 37;

  private long checkSum;

  /**
   * Counts the number of times <code>{@link #append(int)}</code> is executed.
   * It is also used to build <code>{@link #checkSum}</code> and
   * <code>{@link #hashCode}</code>.
   */
  private int count;

  /**
   * Hash code to build;
   */
  private int hashCode;

  /**
   * Constructor.
   */
  public HashCodeCalculator() {
    super();
    hashCode = INITIAL_HASH;
  }

  /**
   * Recalculates <code>{@link #checkSum}</code> and
   * <code>{@link #hashCode}</code> using the specified value.
   *
   * @param value
   *          the specified value.
   */
  public void append(int value) {
    count++;
    int valueToAppend = count * value;

    hashCode = MULTIPLIER * hashCode + (valueToAppend ^ (valueToAppend >>> 16));
    checkSum += valueToAppend;
  }

  /**
   * @return the number that ensures that the combination hashCode/checSum is
   *         unique
   */
  public long getCheckSum() {
    return checkSum;
  }

  /**
   * @return the calculated hash code
   */
  public int getHashCode() {
    return hashCode;
  }
}



import java.util.HashSet;
import java.util.Set;

import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

/**
 * <p>
 * Miscellaneous object utility methods.
 * </p>
 * 
 * @author Elicer Zheng
 */
public abstract class ObjectsUtility {

  private static final String ARRAY_ELEMENT_SEPARATOR = ", ";

  private static final String ARRAY_END = "}";

  private static final String ARRAY_START = "{";

  private static final String EMPTY_ARRAY = "{}";

  private static final int INITIAL_HASH = 7;

  private static final int MULTIPLIER = 31;

  private static final String NULL_ARRAY = "null";

  private static final Set primitivesAndWrappers;

  static {
    primitivesAndWrappers = new HashSet();
    primitivesAndWrappers.add(boolean.class);
    primitivesAndWrappers.add(Boolean.class);
    primitivesAndWrappers.add(byte.class);
    primitivesAndWrappers.add(Byte.class);
    primitivesAndWrappers.add(char.class);
    primitivesAndWrappers.add(Character.class);
    primitivesAndWrappers.add(double.class);
    primitivesAndWrappers.add(Double.class);
    primitivesAndWrappers.add(float.class);
    primitivesAndWrappers.add(Float.class);
    primitivesAndWrappers.add(int.class);
    primitivesAndWrappers.add(Integer.class);
    primitivesAndWrappers.add(long.class);
    primitivesAndWrappers.add(Long.class);
    primitivesAndWrappers.add(short.class);
    primitivesAndWrappers.add(Short.class);
  }

  /**
   * Returns the same value as <code>{@link Boolean#hashCode()}</code>.
   * 
   * @param bool
   *          the given <code>boolean</code>.
   * @return the hash code for the given <code>boolean</code>.
   * @see Boolean#hashCode()
   */
  public static int hashCode(boolean bool) {
    return bool ? 1231 : 1237;
  }

  /**
   * Returns the same value as <code>{@link Double#hashCode()}</code>.
   * 
   * @param dbl
   *          the given <code>double</code>.
   * @return the hash code for the given <code>double</code>.
   * @see Double#hashCode()
   */
  public static int hashCode(double dbl) {
    long bits = Double.doubleToLongBits(dbl);
    return hashCode(bits);
  }

  /**
   * Returns the same value as <code>{@link Float#hashCode()}</code>.
   * 
   * @param flt
   *          the given <code>float</code>.
   * @return the hash code for the given <code>float</code>.
   * @see Float#hashCode()
   */
  public static int hashCode(float flt) {
    return Float.floatToIntBits(flt);
  }

  /**
   * Returns the same value as <code>{@link Long#hashCode()}</code>.
   * 
   * @param lng
   *          the given <code>long</code>.
   * @return the hash code for the given <code>long</code>.
   * @see Long#hashCode()
   */
  public static int hashCode(long lng) {
    return (int) (lng ^ (lng >>> 32));
  }

  /**
   * <p>
   * Returns a <code>StringBuffer</code> containing:
   * <ol>
   * <li>the class name of the given object</li>
   * <li>the character '@'</li>
   * <li>the hex string for the object's identity hash code</li>
   * </ol>
   * </p>
   * <p>
   * This method will return an empty <code>StringBuffer</code> if the given
   * object is <code>null</code>.
   * </p>
   * 
   * @param obj
   *          the given object.
   * @return a <code>StringBuffer</code> containing identity information of
   *         the given object.
   */
  public static StringBuffer identityToString(Object obj) {
    StringBuffer buffer = new StringBuffer();
    if (obj != null) {
      buffer.append(obj.getClass().getName());
      buffer.append("@");
      buffer.append(ObjectUtils.getIdentityHexString(obj));
    }
    return buffer;
  }

  /**
   * Returns <code>true</code> if the given object is an array of primitives.
   * 
   * @param array
   *          the given object to check.
   * @return <code>true</code> if the given object is an array of primitives.
   */
  public static boolean isArrayOfPrimitives(Object array) {
    boolean primitiveArray = false;

    if (array != null) {
      Class clazz = array.getClass();

      primitiveArray = clazz.isArray()
          && clazz.getComponentType().isPrimitive();
    }

    return primitiveArray;
  }

  /**
   * Returns <code>true</code> if the given class is any of the following:
   * <ul>
   * <li><code>boolean</code></li>
   * <li>Boolean</li>
   * <li><code>byte</code></li>
   * <li>Byte</li>
   * <li><code>char</code></li>
   * <li>Character</li>
   * <li><code>double</code></li>
   * <li>Double</li>
   * <li><code>float</code></li>
   * <li>Float</li>
   * <li><code>int</code></li>
   * <li>Integer</li>
   * <li><code>long</code></li>
   * <li>Long</li>
   * <li><code>short</code></li>
   * <li>Short</li>
   * </ul>
   * 
   * @param clazz
   *          the given class.
   * @return <code>true</code> if the given class represents a primitive or a
   *         wrapper, <code>false</code> otherwise.
   */
  public static boolean isPrimitiveOrWrapper(Class clazz) {
    return primitivesAndWrappers.contains(clazz);
  }

  /**
   * <p>
   * Returns a hash code based on the contents of the specified array. For any
   * two <code>boolean</code> arrays <code>a</code> and <code>b</code>
   * such that <code>Arrays.equals(a, b)</code>, it is also the case that
   * <code>Arrays.hashCode(a) == Arrays.hashCode(b)</code>.
   * </p>
   * 
   * <p>
   * If <code>array</code> is <code>null</code>, this method returns 0.
   * </p>
   * 
   * @param array
   *          the array whose hash value to compute.
   * @return a content-based hash code for <code>array</code>.
   * @see #hashCode(boolean)
   */
  public static int nullSafeHashCode(boolean[] array) {
    if (array == null)
      return 0;

    int hash = INITIAL_HASH;
    int arraySize = array.length;
    for (int i = 0; i < arraySize; i++) {
      hash = MULTIPLIER * hash + hashCode(array[i]);
    }

    return hash;
  }

  /**
   * <p>
   * Returns a hash code based on the contents of the specified array. For any
   * two <code>byte</code> arrays <code>a</code> and <code>b</code> such
   * that <code>Arrays.equals(a, b)</code>, it is also the case that
   * <code>Arrays.hashCode(a) == Arrays.hashCode(b)</code>.
   * </p>
   * 
   * <p>
   * If <code>array</code> is <code>null</code>, this method returns 0.
   * </p>
   * 
   * @param array
   *          the array whose hash value to compute.
   * @return a content-based hash code for <code>array</code>.
   */
  public static int nullSafeHashCode(byte[] array) {
    if (array == null)
      return 0;

    int hash = INITIAL_HASH;
    int arraySize = array.length;
    for (int i = 0; i < arraySize; i++) {
      hash = MULTIPLIER * hash + array[i];
    }

    return hash;
  }

  /**
   * <p>
   * Returns a hash code based on the contents of the specified array. For any
   * two <code>char</code> arrays <code>a</code> and <code>b</code> such
   * that <code>Arrays.equals(a, b)</code>, it is also the case that
   * <code>Arrays.hashCode(a) == Arrays.hashCode(b)</code>.
   * </p>
   * 
   * <p>
   * If <code>array</code> is <code>null</code>, this method returns 0.
   * </p>
   * 
   * @param array
   *          the array whose hash value to compute.
   * @return a content-based hash code for <code>array</code>.
   */
  public static int nullSafeHashCode(char[] array) {
    if (array == null)
      return 0;

    int hash = INITIAL_HASH;
    int arraySize = array.length;
    for (int i = 0; i < arraySize; i++) {
      hash = MULTIPLIER * hash + array[i];
    }

    return hash;
  }

  /**
   * <p>
   * Returns a hash code based on the contents of the specified array. For any
   * two <code>double</code> arrays <code>a</code> and <code>b</code> such
   * that <code>Arrays.equals(a, b)</code>, it is also the case that
   * <code>Arrays.hashCode(a) == Arrays.hashCode(b)</code>.
   * </p>
   * 
   * <p>
   * If <code>array</code> is <code>null</code>, this method returns 0.
   * </p>
   * 
   * @param array
   *          the array whose hash value to compute.
   * @return a content-based hash code for <code>array</code>.
   * @see #hashCode(double)
   */
  public static int nullSafeHashCode(double[] array) {
    if (array == null)
      return 0;

    int hash = INITIAL_HASH;
    int arraySize = array.length;
    for (int i = 0; i < arraySize; i++) {
      hash = MULTIPLIER * hash + hashCode(array[i]);
    }

    return hash;
  }

  /**
   * <p>
   * Returns a hash code based on the contents of the specified array. For any
   * two <code>float</code> arrays <code>a</code> and <code>b</code> such
   * that <code>Arrays.equals(a, b)</code>, it is also the case that
   * <code>Arrays.hashCode(a) == Arrays.hashCode(b)</code>.
   * </p>
   * 
   * <p>
   * If <code>array</code> is <code>null</code>, this method returns 0.
   * </p>
   * 
   * @param array
   *          the array whose hash value to compute.
   * @return a content-based hash code for <code>array</code>.
   * @see #hashCode(float)
   */
  public static int nullSafeHashCode(float[] array) {
    if (array == null)
      return 0;

    int hash = INITIAL_HASH;
    int arraySize = array.length;
    for (int i = 0; i < arraySize; i++) {
      hash = MULTIPLIER * hash + hashCode(array[i]);
    }

    return hash;
  }

  /**
   * <p>
   * Returns a hash code based on the contents of the specified array. For any
   * two <code>int</code> arrays <code>a</code> and <code>b</code> such
   * that <code>Arrays.equals(a, b)</code>, it is also the case that
   * <code>Arrays.hashCode(a) == Arrays.hashCode(b)</code>.
   * </p>
   * 
   * <p>
   * If <code>array</code> is <code>null</code>, this method returns 0.
   * </p>
   * 
   * @param array
   *          the array whose hash value to compute.
   * @return a content-based hash code for <code>array</code>.
   */
  public static int nullSafeHashCode(int[] array) {
    if (array == null)
      return 0;

    int hash = INITIAL_HASH;
    int arraySize = array.length;
    for (int i = 0; i < arraySize; i++) {
      hash = MULTIPLIER * hash + array[i];
    }

    return hash;
  }

  /**
   * <p>
   * Returns a hash code based on the contents of the specified array. For any
   * two <code>long</code> arrays <code>a</code> and <code>b</code> such
   * that <code>Arrays.equals(a, b)</code>, it is also the case that
   * <code>Arrays.hashCode(a) == Arrays.hashCode(b)</code>.
   * </p>
   * 
   * <p>
   * If <code>array</code> is <code>null</code>, this method returns 0.
   * </p>
   * 
   * @param array
   *          the array whose hash value to compute.
   * @return a content-based hash code for <code>array</code>.
   * @see #hashCode(long)
   */
  public static int nullSafeHashCode(long[] array) {
    if (array == null)
      return 0;

    int hash = INITIAL_HASH;
    int arraySize = array.length;
    for (int i = 0; i < arraySize; i++) {
      hash = MULTIPLIER * hash + hashCode(array[i]);
    }

    return hash;
  }

  /**
   * <p>
   * Returns the value of <code>{@link Object#hashCode()}</code>. If the
   * object is an array, this method will delegate to any of the
   * <code>nullSafeHashCode</code> methods for arrays in this class.
   * </p>
   * 
   * <p>
   * If the object is <code>null</code>, this method returns 0.
   * </p>
   * 
   * @param obj
   *          the object whose hash value to compute.
   * @return the hash code of the given object.
   * @see #nullSafeHashCode(boolean[])
   * @see #nullSafeHashCode(byte[])
   * @see #nullSafeHashCode(char[])
   * @see #nullSafeHashCode(double[])
   * @see #nullSafeHashCode(float[])
   * @see #nullSafeHashCode(int[])
   * @see #nullSafeHashCode(long[])
   * @see #nullSafeHashCode(Object[])
   * @see #nullSafeHashCode(short[])
   */
  public static int nullSafeHashCode(Object obj) {
    if (obj == null)
      return 0;

    if (obj instanceof boolean[]) {
      return nullSafeHashCode((boolean[]) obj);
    }
    if (obj instanceof byte[]) {
      return nullSafeHashCode((byte[]) obj);
    }
    if (obj instanceof char[]) {
      return nullSafeHashCode((char[]) obj);
    }
    if (obj instanceof double[]) {
      return nullSafeHashCode((double[]) obj);
    }
    if (obj instanceof float[]) {
      return nullSafeHashCode((float[]) obj);
    }
    if (obj instanceof int[]) {
      return nullSafeHashCode((int[]) obj);
    }
    if (obj instanceof long[]) {
      return nullSafeHashCode((long[]) obj);
    }
    if (obj instanceof short[]) {
      return nullSafeHashCode((short[]) obj);
    }
    if (obj instanceof Object[]) {
      return nullSafeHashCode((Object[]) obj);
    }

    return obj.hashCode();
  }

  /**
   * <p>
   * Returns a hash code based on the contents of the specified array. For any
   * two arrays <code>a</code> and <code>b</code> such that
   * <code>Arrays.equals(a, b)</code>, it is also the case that
   * <code>Arrays.hashCode(a) == Arrays.hashCode(b)</code>.
   * </p>
   * <p>
   * The value returned by this method is equal to the value that would be
   * returned by <code>Arrays.asList(a).hashCode()</code>, unless
   * <code>array</code> is <code>null</code>, in which case <code>0</code>
   * is returned.
   * </p>
   * 
   * @param array
   *          the array whose content-based hash code to compute.
   * @return a content-based hash code for <code>array</code>.
   */
  public static int nullSafeHashCode(Object[] array) {
    if (array == null)
      return 0;

    int hash = INITIAL_HASH;
    int arraySize = array.length;
    for (int i = 0; i < arraySize; i++) {
      hash = MULTIPLIER * hash + nullSafeHashCode(array[i]);
    }

    return hash;
  }

  /**
   * <p>
   * Returns a hash code based on the contents of the specified array. For any
   * two <code>short</code> arrays <code>a</code> and <code>b</code> such
   * that <code>Arrays.equals(a, b)</code>, it is also the case that
   * <code>Arrays.hashCode(a) == Arrays.hashCode(b)</code>.
   * </p>
   * 
   * <p>
   * If <code>array</code> is <code>null</code>, this method returns 0.
   * 
   * @param array
   *          the array whose hash value to compute
   * @return a content-based hash code for <code>array</code>
   */
  public static int nullSafeHashCode(short[] array) {
    if (array == null)
      return 0;

    int hash = INITIAL_HASH;
    int arraySize = array.length;
    for (int i = 0; i < arraySize; i++) {
      hash = MULTIPLIER * hash + array[i];
    }

    return hash;
  }

  /**
   * Returns a string representation of the contents of the specified array. The
   * string representation consists of a list of the array's elements, enclosed
   * in curly braces (<code>"{}"</code>). Adjacent elements are separated by
   * the characters <code>", "</code> (a comma followed by a space). Returns
   * <code>"null"</code> if <code>array</code> is <code>null</code>.
   * 
   * @param array
   *          the array whose string representation to return.
   * @return a string representation of <code>array</code>.
   */
  public static String nullSafeToString(boolean[] array) {
    if (array == null)
      return NULL_ARRAY;

    int length = array.length;
    if (length == 0)
      return EMPTY_ARRAY;

    StringBuffer buffer = new StringBuffer();
    for (int i = 0; i < length; i++) {
      if (i == 0)
        buffer.append(ARRAY_START);
      else
        buffer.append(ARRAY_ELEMENT_SEPARATOR);

      buffer.append(array[i]);
    }

    buffer.append(ARRAY_END);
    return buffer.toString();
  }

  /**
   * Returns a string representation of the contents of the specified array. The
   * string representation consists of a list of the array's elements, enclosed
   * in curly braces (<code>"{}"</code>). Adjacent elements are separated by
   * the characters <code>", "</code> (a comma followed by a space). Returns
   * <code>"null"</code> if <code>array</code> is <code>null</code>.
   * 
   * @param array
   *          the array whose string representation to return.
   * @return a string representation of <code>array</code>.
   */
  public static String nullSafeToString(byte[] array) {
    if (array == null)
      return NULL_ARRAY;

    int length = array.length;
    if (length == 0)
      return EMPTY_ARRAY;

    StringBuffer buffer = new StringBuffer();
    for (int i = 0; i < length; i++) {
      if (i == 0)
        buffer.append(ARRAY_START);
      else
        buffer.append(ARRAY_ELEMENT_SEPARATOR);

      buffer.append(array[i]);
    }

    buffer.append(ARRAY_END);
    return buffer.toString();
  }

  /**
   * Returns a string representation of the contents of the specified array. The
   * string representation consists of a list of the array's elements, enclosed
   * in curly braces (<code>"{}"</code>). Adjacent elements are separated by
   * the characters <code>", "</code> (a comma followed by a space). Returns
   * <code>"null"</code> if <code>array</code> is <code>null</code>.
   * 
   * @param array
   *          the array whose string representation to return.
   * @return a string representation of <code>array</code>.
   */
  public static String nullSafeToString(char[] array) {
    if (array == null)
      return NULL_ARRAY;

    int length = array.length;
    if (length == 0)
      return EMPTY_ARRAY;

    StringBuffer buffer = new StringBuffer();
    for (int i = 0; i < length; i++) {
      if (i == 0)
        buffer.append(ARRAY_START);
      else
        buffer.append(ARRAY_ELEMENT_SEPARATOR);

      buffer.append("'" + array[i] + "'");
    }

    buffer.append(ARRAY_END);
    return buffer.toString();
  }

  /**
   * Returns a string representation of the contents of the specified array. The
   * string representation consists of a list of the array's elements, enclosed
   * in curly braces (<code>"{}"</code>). Adjacent elements are separated by
   * the characters <code>", "</code> (a comma followed by a space). Returns
   * <code>"null"</code> if <code>array</code> is <code>null</code>.
   * 
   * @param array
   *          the array whose string representation to return.
   * @return a string representation of <code>array</code>.
   */
  public static String nullSafeToString(double[] array) {
    if (array == null)
      return NULL_ARRAY;

    int length = array.length;
    if (length == 0)
      return EMPTY_ARRAY;

    StringBuffer buffer = new StringBuffer();
    for (int i = 0; i < length; i++) {
      if (i == 0)
        buffer.append(ARRAY_START);
      else
        buffer.append(ARRAY_ELEMENT_SEPARATOR);

      buffer.append(array[i]);
    }

    buffer.append(ARRAY_END);
    return buffer.toString();
  }

  /**
   * Returns a string representation of the contents of the specified array. The
   * string representation consists of a list of the array's elements, enclosed
   * in curly braces (<code>"{}"</code>). Adjacent elements are separated by
   * the characters <code>", "</code> (a comma followed by a space). Returns
   * <code>"null"</code> if <code>array</code> is <code>null</code>.
   * 
   * @param array
   *          the array whose string representation to return.
   * @return a string representation of <code>array</code>.
   */
  public static String nullSafeToString(float[] array) {
    if (array == null)
      return NULL_ARRAY;

    int length = array.length;
    if (length == 0)
      return EMPTY_ARRAY;

    StringBuffer buffer = new StringBuffer();
    for (int i = 0; i < length; i++) {
      if (i == 0)
        buffer.append(ARRAY_START);
      else
        buffer.append(ARRAY_ELEMENT_SEPARATOR);

      buffer.append(array[i]);
    }

    buffer.append(ARRAY_END);
    return buffer.toString();
  }

  /**
   * Returns a string representation of the contents of the specified array. The
   * string representation consists of a list of the array's elements, enclosed
   * in curly braces (<code>"{}"</code>). Adjacent elements are separated by
   * the characters <code>", "</code> (a comma followed by a space). Returns
   * <code>"null"</code> if <code>array</code> is <code>null</code>.
   * 
   * @param array
   *          the array whose string representation to return.
   * @return a string representation of <code>array</code>.
   */
  public static String nullSafeToString(int[] array) {
    if (array == null)
      return NULL_ARRAY;

    int length = array.length;
    if (length == 0)
      return EMPTY_ARRAY;

    StringBuffer buffer = new StringBuffer();
    for (int i = 0; i < length; i++) {
      if (i == 0)
        buffer.append(ARRAY_START);
      else
        buffer.append(ARRAY_ELEMENT_SEPARATOR);

      buffer.append(array[i]);
    }

    buffer.append(ARRAY_END);
    return buffer.toString();
  }

  /**
   * Returns a string representation of the contents of the specified array. The
   * string representation consists of a list of the array's elements, enclosed
   * in curly braces (<code>"{}"</code>). Adjacent elements are separated by
   * the characters <code>", "</code> (a comma followed by a space). Returns
   * <code>"null"</code> if <code>array</code> is <code>null</code>.
   * 
   * @param array
   *          the array whose string representation to return.
   * @return a string representation of <code>array</code>.
   */
  public static String nullSafeToString(long[] array) {
    if (array == null)
      return NULL_ARRAY;

    int length = array.length;
    if (length == 0)
      return EMPTY_ARRAY;

    StringBuffer buffer = new StringBuffer();
    for (int i = 0; i < length; i++) {
      if (i == 0)
        buffer.append(ARRAY_START);
      else
        buffer.append(ARRAY_ELEMENT_SEPARATOR);

      buffer.append(array[i]);
    }

    buffer.append(ARRAY_END);
    return buffer.toString();
  }

  /**
   * Returns a string representation of the contents of the specified array. The
   * string representation consists of a list of the array's elements, enclosed
   * in curly braces (<code>"{}"</code>). Adjacent elements are separated by
   * the characters <code>", "</code> (a comma followed by a space). Returns
   * <code>"null"</code> if <code>array</code> is <code>null</code>.
   * 
   * @param array
   *          the array whose string representation to return.
   * @return a string representation of <code>array</code>.
   */
  public static String nullSafeToString(Object[] array) {
    if (array == null)
      return NULL_ARRAY;

    int length = array.length;
    if (length == 0)
      return EMPTY_ARRAY;

    StringBuffer buffer = new StringBuffer();
    for (int i = 0; i < length; i++) {
      if (i == 0)
        buffer.append(ARRAY_START);
      else
        buffer.append(ARRAY_ELEMENT_SEPARATOR);

      buffer.append(StringUtils.quoteIfString(array[i]));
    }

    buffer.append(ARRAY_END);
    return buffer.toString();
  }

  /**
   * Returns a string representation of the contents of the specified array. The
   * string representation consists of a list of the array's elements, enclosed
   * in curly braces (<code>"{}"</code>). Adjacent elements are separated by
   * the characters <code>", "</code> (a comma followed by a space). Returns
   * <code>"null"</code> if <code>array</code> is <code>null</code>.
   * 
   * @param array
   *          the array whose string representation to return.
   * @return a string representation of <code>array</code>.
   */
  public static String nullSafeToString(short[] array) {
    if (array == null)
      return NULL_ARRAY;

    int length = array.length;
    if (length == 0)
      return EMPTY_ARRAY;

    StringBuffer buffer = new StringBuffer();
    for (int i = 0; i < length; i++) {
      if (i == 0)
        buffer.append(ARRAY_START);
      else
        buffer.append(ARRAY_ELEMENT_SEPARATOR);

      buffer.append(array[i]);
    }

    buffer.append(ARRAY_END);
    return buffer.toString();
  }

  /**
   * Returns a string representation of the contents of the specified array. The
   * string representation consists of a list of the array's elements, enclosed
   * in curly braces (<code>"{}"</code>). Adjacent elements are separated by
   * the characters <code>", "</code> (a comma followed by a space). Returns
   * <code>"null"</code> if <code>array</code> is <code>null</code>.
   * 
   * @param array
   *          the array whose string representation to return.
   * @return a string representation of <code>array</code>.
   */
  public static String nullSafeToString(String[] array) {
    if (array == null)
      return NULL_ARRAY;

    int length = array.length;
    if (length == 0)
      return EMPTY_ARRAY;

    StringBuffer buffer = new StringBuffer();
    for (int i = 0; i < length; i++) {
      if (i == 0)
        buffer.append(ARRAY_START);
      else
        buffer.append(ARRAY_ELEMENT_SEPARATOR);

      buffer.append(StringUtils.quote(array[i]));
    }

    buffer.append(ARRAY_END);
    return buffer.toString();
  }
}



import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;

import org.springframework.util.ReflectionUtils;



/**
 * <p>
 * Reflection-related utility methods,used to build the hash code for the input parameter.
 * </p>
 *
 * 
 * @author Elicer Zheng
 */
public abstract class ReflectionsUtility {

  private static final int INITIAL_HASH = 7;

  private static final int MULTIPLIER = 31;

  /**
   * <p>
   * This method uses reflection to build a valid hash code.
   * </p>
   *
   * <p>
   * It uses <code>AccessibleObject.setAccessible</code> to gain access to
   * private fields. This means that it will throw a security exception if run
   * under a security manager, if the permissions are not set up correctly. It
   * is also not as efficient as testing explicitly.
   * </p>
   *
   * <p>
   * Transient members will not be used, as they are likely derived fields,
   * and not part of the value of the <code>Object</code>.
   * </p>
   *
   * <p>
   * Static fields will not be tested. Superclass fields will be included.
   * </p>
   *
   * @param obj
   *          the object to create a <code>hashCode</code> for
   * @return the generated hash code, or zero if the given object is
   *         <code>null</code>
   */
  public static int reflectionHashCode(Object obj) {
    if (obj == null)
      return 0;

    Class targetClass = obj.getClass();
    if (ObjectsUtility.isArrayOfPrimitives(obj)
        || ObjectsUtility.isPrimitiveOrWrapper(targetClass)) {
      return ObjectsUtility.nullSafeHashCode(obj);
    }

    if (targetClass.isArray()) {
      return reflectionHashCode((Object[]) obj);
    }

    if (obj instanceof Collection) {
      return reflectionHashCode((Collection) obj);
    }

    if (obj instanceof Map) {
      return reflectionHashCode((Map) obj);
    }

		// determine whether the object's class declares hashCode() or has a
		// superClass other than java.lang.Object that declares hashCode()
		Class clazz = (obj instanceof Class)? (Class) obj : obj.getClass();
		Method hashCodeMethod = ReflectionUtils.findMethod(clazz,
				"hashCode", new Class[0]);

		if (hashCodeMethod != null) {
			return obj.hashCode();
		}

		// could not find a hashCode other than the one declared by java.lang.Object
		int hash = INITIAL_HASH;

    try {
      while (targetClass != null) {
        Field[] fields = targetClass.getDeclaredFields();
        AccessibleObject.setAccessible(fields, true);

        for (int i = 0; i < fields.length; i++) {
          Field field = fields[i];
          int modifiers = field.getModifiers();

          if (!Modifier.isStatic(modifiers) && !Modifier.isTransient(modifiers)) {
            hash = MULTIPLIER * hash + reflectionHashCode(field.get(obj));
          }
        }
        targetClass = targetClass.getSuperclass();
      }
    } catch (IllegalAccessException exception) {
      // ///CLOVER:OFF
      ReflectionUtils.handleReflectionException(exception);
      // ///CLOVER:ON
    }

    return hash;
  }

  private static int reflectionHashCode(Collection collection) {
    int hash = INITIAL_HASH;

    for (Iterator i = collection.iterator(); i.hasNext();) {
      hash = MULTIPLIER * hash + reflectionHashCode(i.next());
    }

    return hash;
  }

  private static int reflectionHashCode(Map map) {
    int hash = INITIAL_HASH;

    for (Iterator i = map.entrySet().iterator(); i.hasNext();) {
      Map.Entry entry = (Map.Entry) i.next();
      hash = MULTIPLIER * hash + reflectionHashCode(entry);
    }

    return hash;
  }

  private static int reflectionHashCode(Map.Entry entry) {
    int hash = INITIAL_HASH;
    hash = MULTIPLIER * hash + reflectionHashCode(entry.getKey());
    hash = MULTIPLIER * hash + reflectionHashCode(entry.getValue());
    return hash;
  }

  private static int reflectionHashCode(Object[] array) {
    int hash = INITIAL_HASH;
    int arraySize = array.length;
    for (int i = 0; i < arraySize; i++) {
      hash = MULTIPLIER * hash + reflectionHashCode(array[i]);
    }

    return hash;
  }
}


0
0
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics