Package org.powermock.reflect.internal

Source Code of org.powermock.reflect.internal.WhiteboxImpl

/*
* Copyright 2008 the original author or authors.
*
* 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 org.powermock.reflect.internal;

import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import org.objenesis.Objenesis;
import org.objenesis.ObjenesisStd;
import org.objenesis.instantiator.ObjectInstantiator;
import org.powermock.reflect.exceptions.ConstructorNotFoundException;
import org.powermock.reflect.exceptions.FieldNotFoundException;
import org.powermock.reflect.exceptions.MethodInvocationException;
import org.powermock.reflect.exceptions.MethodNotFoundException;
import org.powermock.reflect.exceptions.TooManyConstructorsFoundException;
import org.powermock.reflect.exceptions.TooManyFieldsFoundException;
import org.powermock.reflect.exceptions.TooManyMethodsFoundException;
import org.powermock.reflect.internal.matcherstrategies.AllFieldsMatcherStrategy;
import org.powermock.reflect.internal.matcherstrategies.AssignableToFieldTypeMatcherStrategy;
import org.powermock.reflect.internal.matcherstrategies.FieldAnnotationMatcherStrategy;
import org.powermock.reflect.internal.matcherstrategies.FieldMatcherStrategy;
import org.powermock.reflect.internal.matcherstrategies.FieldNameMatcherStrategy;
import org.powermock.reflect.internal.matcherstrategies.FieldTypeMatcherStrategy;
import org.powermock.reflect.internal.primitivesupport.PrimitiveWrapper;
import org.powermock.reflect.spi.ProxyFramework;

/**
* Various utilities for accessing internals of a class. Basically a simplified
* reflection utility intended for tests.
*/
public class WhiteboxImpl {

  private static ProxyFramework proxyFramework = null;

  /**
   * Convenience method to get a method from a class type without having to
   * catch the checked exceptions otherwise required. These exceptions are
   * wrapped as runtime exceptions.
   * <p>
   * The method will first try to look for a declared method in the same
   * class. If the method is not declared in this class it will look for the
   * method in the super class. This will continue throughout the whole class
   * hierarchy. If the method is not found an {@link IllegalArgumentException}
   * is thrown. Since the method name is not specified an
   * {@link IllegalArgumentException} is thrown if two or more methods matches
   * the same parameter types in the same class.
   *
   * @param type
   *            The type of the class where the method is located.
   * @param parameterTypes
   *            All parameter types of the method (may be <code>null</code>).
   * @return A <code>java.lang.reflect.Method</code>.
   * @throws MethodNotFoundException
   *             If a method cannot be found in the hierarchy.
   * @throws TooManyMethodsFoundException
   *             If several methods were found.
   */
  public static Method getMethod(Class<?> type, Class<?>... parameterTypes) {
    Class<?> thisType = type;
    if (parameterTypes == null) {
      parameterTypes = new Class<?>[0];
    }

    List<Method> foundMethods = new LinkedList<Method>();
    while (thisType != null) {
      Method[] methodsToTraverse = null;
      if (thisType.isInterface()) {
        // Interfaces only contain public (and abstract) methods, no
        // need to traverse the hierarchy.
        methodsToTraverse = getAllPublicMethods(thisType);
      } else {
        methodsToTraverse = thisType.getDeclaredMethods();
      }
      for (Method method : methodsToTraverse) {
        if (checkIfTypesAreSame(parameterTypes, method.getParameterTypes())) {
          foundMethods.add(method);
          if (foundMethods.size() == 1) {
            method.setAccessible(true);
          }
        }

      }
      if (foundMethods.size() == 1) {
        return foundMethods.get(0);
      } else if (foundMethods.size() > 1) {
        break;
      }
      thisType = thisType.getSuperclass();
    }

    if (foundMethods.isEmpty()) {
      throw new MethodNotFoundException("No method was found with argument types: [ "
          + getArgumentsAsString((Object[]) parameterTypes) + " ] in class "
          + getUnmockedType(type).getName());
    } else {
      throwExceptionWhenMultipleMethodMatchesFound("method name", foundMethods.toArray(new Method[foundMethods
          .size()]));
    }
    // Will never happen
    return null;
  }

  /**
   * Convenience method to get a method from a class type without having to
   * catch the checked exceptions otherwise required. These exceptions are
   * wrapped as runtime exceptions.
   * <p>
   * The method will first try to look for a declared method in the same
   * class. If the method is not declared in this class it will look for the
   * method in the super class. This will continue throughout the whole class
   * hierarchy. If the method is not found an {@link IllegalArgumentException}
   * is thrown.
   *
   * @param type
   *            The type of the class where the method is located.
   * @param methodName
   *            The method names.
   * @param parameterTypes
   *            All parameter types of the method (may be <code>null</code>).
   * @return A <code>java.lang.reflect.Method</code>.
   * @throws MethodNotFoundException
   *             If a method cannot be found in the hierarchy.
   */
  public static Method getMethod(Class<?> type, String methodName, Class<?>... parameterTypes) {
    Class<?> thisType = type;
    if (parameterTypes == null) {
      parameterTypes = new Class<?>[0];
    }
    while (thisType != null) {
      Method[] methodsToTraverse = null;
      if (thisType.isInterface()) {
        // Interfaces only contain public (and abstract) methods, no
        // need to traverse the hierarchy.
        methodsToTraverse = getAllPublicMethods(thisType);
      } else {
        methodsToTraverse = thisType.getDeclaredMethods();
      }
      for (Method method : methodsToTraverse) {
        if (methodName.equals(method.getName())
            && checkIfTypesAreSame(parameterTypes, method.getParameterTypes())) {
          method.setAccessible(true);
          return method;
        }
      }
      thisType = thisType.getSuperclass();
    }

    throwExceptionIfMethodWasNotFound(type, methodName, null, new Object[] { parameterTypes });
    return null;
  }

  /**
   * Convenience method to get a field from a class type.
   * <p>
   * The method will first try to look for a declared field in the same class.
   * If the method is not declared in this class it will look for the field in
   * the super class. This will continue throughout the whole class hierarchy.
   * If the field is not found an {@link IllegalArgumentException} is thrown.
   *
   * @param type
   *            The type of the class where the method is located.
   * @param fieldName
   *            The method names.
   * @return A <code>java.lang.reflect.Field</code>.
   * @throws FieldNotFoundException
   *             If a field cannot be found in the hierarchy.
   */
  @SuppressWarnings("unchecked")
  public static Field getField(Class<?> type, String fieldName) {
    LinkedList<Class<?>> examine = new LinkedList<Class<?>>();
    examine.add(type);
    Set<Class<?>> done = new HashSet<Class<?>>();
    while (examine.isEmpty() == false) {
      Class<?> thisType = examine.removeFirst();
      done.add(thisType);
      final Field[] declaredField = thisType.getDeclaredFields();
      for (Field field : declaredField) {
        if (fieldName.equals(field.getName())) {
          field.setAccessible(true);
          return field;
        }
      }
      Set<Class<?>> potential = new HashSet<Class<?>>();
      potential.add(thisType.getSuperclass());
      potential.addAll((Collection) Arrays.asList(thisType.getInterfaces()));
      potential.removeAll(done);
      examine.addAll(potential);
    }

    throwExceptionIfFieldWasNotFound(type, fieldName, null);
    return null;
  }

  /**
   * Create a new instance of a class without invoking its constructor.
   * <p>
   * No byte-code manipulation is needed to perform this operation and thus
   * it's not necessary use the <code>PowerMockRunner</code> or
   * <code>PrepareForTest</code> annotation to use this functionality.
   *
   * @param <T>
   *            The type of the instance to create.
   * @param classToInstantiate
   *            The type of the instance to create.
   * @return A new instance of type T, created without invoking the
   *         constructor.
   */
  @SuppressWarnings("unchecked")
  public static <T> T newInstance(Class<T> classToInstantiate) {
    Objenesis objenesis = new ObjenesisStd();
    ObjectInstantiator thingyInstantiator = objenesis.getInstantiatorOf(classToInstantiate);
    return (T) thingyInstantiator.newInstance();
  }

  /**
   * Convenience method to get a (declared) constructor from a class type
   * without having to catch the checked exceptions otherwise required. These
   * exceptions are wrapped as runtime exceptions. The constructor is also set
   * to accessible.
   *
   * @param type
   *            The type of the class where the constructor is located.
   * @param parameterTypes
   *            All parameter types of the constructor (may be
   *            <code>null</code>).
   * @return A <code>java.lang.reflect.Constructor</code>.
   * @throws ConstructorNotFoundException
   *             if the constructor cannot be found.
   */
  public static Constructor<?> getConstructor(Class<?> type, Class<?>... parameterTypes) {
    try {
      final Constructor<?> constructor = WhiteboxImpl.getUnmockedType(type)
          .getDeclaredConstructor(parameterTypes);
      constructor.setAccessible(true);
      return constructor;
    } catch (RuntimeException e) {
      throw (RuntimeException) e;
    } catch (Error e) {
      throw (Error) e;
    } catch (Throwable e) {
      throw new ConstructorNotFoundException("Failed to lookup constructor.", e);
    }
  }

  /**
   * Set the value of a field using reflection. This method will traverse the
   * super class hierarchy until a field with name <tt>fieldName</tt> is
   * found.
   *
   * @param object
   *            the object to modify
   * @param fieldName
   *            the name of the field
   * @param value
   *            the new value of the field
   */
  public static void setInternalState(Object object, String fieldName, Object value) {
    Field foundField = findFieldInHierarchy(object, fieldName);
    setField(object, value, foundField);
  }

  /**
   * Set the value of a field using reflection. This method will traverse the
   * super class hierarchy until the first field of type <tt>fieldType</tt> is
   * found. The <tt>value</tt> will then be assigned to this field.
   *
   * @param object
   *            the object to modify
   * @param fieldType
   *            the type of the field
   * @param value
   *            the new value of the field
   */
  public static void setInternalState(Object object, Class<?> fieldType, Object value) {
    setField(object, value, findFieldInHierarchy(object, new FieldTypeMatcherStrategy(fieldType)));
  }

  /**
   * Set the value of a field using reflection. This method will traverse the
   * super class hierarchy until the first field assignable to the
   * <tt>value</tt> type is found. The <tt>value</tt> will then be assigned to
   * this field.
   *
   * @param object
   *            the object to modify
   * @param value
   *            the new value of the field
   */
  public static void setInternalState(Object object, Object value) {
    setField(object, value, findFieldInHierarchy(object, new AssignableToFieldTypeMatcherStrategy(getType(value))));
  }

  /**
   * Set the value of a field using reflection at at specific place in the
   * class hierarchy (<tt>where</tt>). This first field assignable to
   * <tt>object</tt> will then be set to <tt>value</tt>.
   *
   * @param object
   *            the object to modify
   * @param value
   *            the new value of the field
   * @param where
   *            the class in the hierarchy where the field is defined
   */
  public static void setInternalState(Object object, Object value, Class<?> where) {
    setField(object, value, findField(object, new AssignableToFieldTypeMatcherStrategy(getType(value)), where));
  }

  /**
   * Set the value of a field using reflection at a specific location (
   * <tt>where</tt>) in the class hierarchy. The <tt>value</tt> will then be
   * assigned to this field.
   *
   * @param object
   *            the object to modify
   * @param fieldType
   *            the type of the field the should be set.
   * @param value
   *            the new value of the field
   * @param where
   *            which class in the hierarchy defining the field
   */
  public static void setInternalState(Object object, Class<?> fieldType, Object value, Class<?> where) {
    if (fieldType == null || where == null) {
      throw new IllegalArgumentException("fieldType and where cannot be null");
    }

    setField(object, value, findFieldOrThrowException(fieldType, where));
  }

  /**
   * Set the value of a field using reflection. Use this method when you need
   * to specify in which class the field is declared. This is useful if you
   * have two fields in a class hierarchy that has the same name but you like
   * to modify the latter.
   *
   * @param object
   *            the object to modify
   * @param fieldName
   *            the name of the field
   * @param value
   *            the new value of the field
   * @param where
   *            which class the field is defined
   */
  public static void setInternalState(Object object, String fieldName, Object value, Class<?> where) {
    if (object == null || fieldName == null || fieldName.equals("") || fieldName.startsWith(" ")) {
      throw new IllegalArgumentException("object, field name, and \"where\" must not be empty or null.");
    }

    final Field field = getField(fieldName, where);
    try {
      field.set(object, value);
    } catch (Exception e) {
      throw new RuntimeException("Internal Error: Failed to set field in method setInternalState.", e);
    }
  }

  /**
   * Get the value of a field using reflection. This method will iterate
   * through the entire class hierarchy and return the value of the first
   * field named <tt>fieldName</tt>. If you want to get a specific field value
   * at specific place in the class hierarchy please refer to
   * {@link #getInternalState(Object, String, Class)}.
   *
   *
   * @param object
   *            the object to modify
   * @param fieldName
   *            the name of the field
   */
  public static Object getInternalState(Object object, String fieldName) {
    Field foundField = findFieldInHierarchy(object, fieldName);
    try {
      return foundField.get(object);
    } catch (IllegalAccessException e) {
      throw new RuntimeException("Internal error: Failed to get field in method getInternalState.", e);
    }
  }

  private static Field findFieldInHierarchy(Object object, String fieldName) {
    return findFieldInHierarchy(object, new FieldNameMatcherStrategy(fieldName));
  }

  private static Field findFieldInHierarchy(Object object, FieldMatcherStrategy strategy) {
    return findSingleFieldUsingStrategy(strategy, object, true, getType(object));
  }

  private static Field findField(Object object, FieldMatcherStrategy strategy, Class<?> where) {
    return findSingleFieldUsingStrategy(strategy, object, false, where);
  }

  private static Field findSingleFieldUsingStrategy(FieldMatcherStrategy strategy, Object object,
      boolean checkHierarchy, Class<?> startClass) {
    if (object == null) {
      throw new IllegalArgumentException("The object containing the field cannot be null");
    }
    Field foundField = null;
    final Class<?> originalStartClass = startClass;
    while (startClass != null) {
      final Field[] declaredFields = startClass.getDeclaredFields();
      for (Field field : declaredFields) {
        if (strategy.matches(field) && hasFieldProperModifier(object, field)) {
          if (foundField != null) {
            throw new TooManyFieldsFoundException("Two or more fields matching " + strategy + ".");
          }
          foundField = field;
        }
      }
      if (foundField != null) {
        break;
      } else if (checkHierarchy == false) {
        break;
      }
      startClass = startClass.getSuperclass();
    }
    if (foundField == null) {
      strategy.notFound(originalStartClass);
    }
    foundField.setAccessible(true);
    return foundField;
  }

  private static Set<Field> findAllFieldsUsingStrategy(FieldMatcherStrategy strategy, Object object,
      boolean checkHierarchy, Class<?> startClass) {
    if (object == null) {
      throw new IllegalArgumentException("The object containing the field cannot be null");
    }
    final Set<Field> foundFields = new LinkedHashSet<Field>();
    while (startClass != null) {
      final Field[] declaredFields = startClass.getDeclaredFields();
      for (Field field : declaredFields) {
        if (strategy.matches(field) && hasFieldProperModifier(object, field)) {
          field.setAccessible(true);
          foundFields.add(field);
        }
      }
      if (!checkHierarchy) {
        break;
      }
      startClass = startClass.getSuperclass();
    }

    return Collections.unmodifiableSet(foundFields);
  }

  private static boolean hasFieldProperModifier(Object object, Field field) {
    return ((object instanceof Class && Modifier.isStatic(field.getModifiers())) || ((object instanceof Class == false && Modifier
        .isStatic(field.getModifiers()) == false)));
  }

  /**
   * Get the value of a field using reflection. Use this method when you need
   * to specify in which class the field is declared. This might be useful
   * when you have mocked the instance you are trying to access.
   *
   * @param object
   *            the object to modify
   * @param fieldName
   *            the name of the field
   * @param where
   *            which class the field is defined
   */
  public static Object getInternalState(Object object, String fieldName, Class<?> where) {
    return getInternalState(object, fieldName, where, Object.class);
  }

  /**
   * Get the value of a field using reflection. This method will traverse the
   * super class hierarchy until the first field of type <tt>fieldType</tt> is
   * found. The value of this field will be returned.
   *
   * @param object
   *            the object to modify
   * @param fieldType
   *            the type of the field
   */
  @SuppressWarnings("unchecked")
  public static <T> T getInternalState(Object object, Class<T> fieldType) {
    Field foundField = findFieldInHierarchy(object, new FieldTypeMatcherStrategy(fieldType));
    try {
      return (T) foundField.get(object);
    } catch (IllegalAccessException e) {
      throw new RuntimeException("Internal error: Failed to get field in method getInternalState.", e);
    }
  }

  /**
   * Get the value of a field using reflection. Use this method when you need
   * to specify in which class the field is declared. The first field matching
   * the <tt>fieldType</tt> in <tt>where</tt> will is the field whose value
   * will be returned.
   *
   * @param <T>
   *            the expected type of the field
   * @param object
   *            the object to modify
   * @param fieldType
   *            the type of the field
   * @param where
   *            which class the field is defined
   */
  @SuppressWarnings("unchecked")
  public static <T> T getInternalState(Object object, Class<T> fieldType, Class<?> where) {
    if (object == null) {
      throw new IllegalArgumentException("object and type are not allowed to be null");
    }

    try {
      return (T) findFieldOrThrowException(fieldType, where).get(object);
    } catch (IllegalAccessException e) {
      throw new RuntimeException("Internal error: Failed to get field in method getInternalState.", e);
    }
  }

  /**
   * Get the value of a field using reflection. Use this method when you need
   * to specify in which class the field is declared. This might be useful
   * when you have mocked the instance you are trying to access. Use this
   * method to avoid casting.
   *
   * @param <T>
   *            the expected type of the field
   * @param object
   *            the object to modify
   * @param fieldName
   *            the name of the field
   * @param where
   *            which class the field is defined
   * @param type
   *            the expected type of the field
   */
  @SuppressWarnings("unchecked")
  public static <T> T getInternalState(Object object, String fieldName, Class<?> where, Class<T> type) {
    if (object == null || fieldName == null || fieldName.equals("") || fieldName.startsWith(" ")) {
      throw new IllegalArgumentException("object, field name, and \"where\" must not be empty or null.");
    }

    if (type == null) {
      throw new IllegalArgumentException("type cannot be null.");
    }

    Field field = null;
    try {
      field = where.getDeclaredField(fieldName);
      field.setAccessible(true);
      return (T) field.get(object);
    } catch (NoSuchFieldException e) {
      throw new FieldNotFoundException("Field '" + fieldName + "' was not found in class " + where.getName()
          + ".");
    } catch (Exception e) {
      throw new RuntimeException("Internal error: Failed to get field in method getInternalState.", e);
    }
  }

  /**
   * Invoke a private or inner class method without the need to specify the
   * method name. This is thus a more refactor friendly version of the
   * {@link #invokeMethod(Object, String, Object...)} method and is recommend
   * over this method for that reason. This method might be useful to test
   * private methods.
   *
   * @throws Throwable
   */
  public static synchronized Object invokeMethod(Object tested, Object... arguments) throws Exception {
    return doInvokeMethod(tested, null, null, arguments);
  }

  /**
   * Invoke a private or inner class method without the need to specify the
   * method name. This is thus a more refactor friendly version of the
   * {@link #invokeMethod(Object, String, Object...)} method and is recommend
   * over this method for that reason. This method might be useful to test
   * private methods.
   */
  public static synchronized Object invokeMethod(Class<?> tested, Object... arguments) throws Exception {
    return doInvokeMethod(tested, null, null, arguments);
  }

  /**
   * Invoke a private or inner class method. This might be useful to test
   * private methods.
   *
   * @throws Throwable
   */
  public static synchronized Object invokeMethod(Object tested, String methodToExecute, Object... arguments)
      throws Exception {
    return doInvokeMethod(tested, null, methodToExecute, arguments);
  }

  /**
   * Invoke a private or inner class method in cases where power mock cannot
   * automatically determine the type of the parameters, for example when
   * mixing primitive types and wrapper types in the same method. For most
   * situations use {@link #invokeMethod(Class, String, Object...)} instead.
   *
   * @throws Exception
   *             Exception that may occur when invoking this method.
   */
  public static synchronized Object invokeMethod(Object tested, String methodToExecute, Class<?>[] argumentTypes,
      Object... arguments) throws Exception {
    final Class<?> unmockedType = getType(tested);
    Method method = getMethod(unmockedType, methodToExecute, argumentTypes);
    if (method == null) {
      throwExceptionIfMethodWasNotFound(unmockedType, methodToExecute, null, arguments);
    }
    return performMethodInvocation(tested, method, arguments);
  }

  /**
   * Invoke a private or inner class method in a subclass (defined by
   * <code>definedIn</code>) in cases where power mock cannot automatically
   * determine the type of the parameters, for example when mixing primitive
   * types and wrapper types in the same method. For most situations use
   * {@link #invokeMethod(Class, String, Object...)} instead.
   *
   * @throws Exception
   *             Exception that may occur when invoking this method.
   */
  public static synchronized Object invokeMethod(Object tested, String methodToExecute, Class<?> definedIn,
      Class<?>[] argumentTypes, Object... arguments) throws Exception {
    Method method = getMethod(definedIn, methodToExecute, argumentTypes);
    if (method == null) {
      throwExceptionIfMethodWasNotFound(definedIn, methodToExecute, null, arguments);
    }
    return performMethodInvocation(tested, method, arguments);
  }

  /**
   * Invoke a private or inner class method in that is located in a subclass
   * of the tested instance. This might be useful to test private methods.
   *
   * @throws Exception
   *             Exception that may occur when invoking this method.
   */
  public static synchronized Object invokeMethod(Object tested, Class<?> declaringClass, String methodToExecute,
      Object... arguments) throws Exception {
    return doInvokeMethod(tested, declaringClass, methodToExecute, arguments);
  }

  /**
   * Invoke a private method in that is located in a subclass of an instance.
   * This might be useful to test overloaded private methods.
   * <p>
   * Use this for overloaded methods only, if possible use
   * {@link #invokeMethod(Object, Object...)} or
   * {@link #invokeMethod(Object, String, Object...)} instead.
   *
   * @throws Exception
   *             Exception that may occur when invoking this method.
   */
  public static synchronized Object invokeMethod(Object object, Class<?> declaringClass, String methodToExecute,
      Class<?>[] parameterTypes, Object... arguments) throws Exception {
    if (object == null) {
      throw new IllegalArgumentException("object cannot be null");
    }

    final Method methodToInvoke = getMethod(declaringClass, methodToExecute, parameterTypes);
    // Invoke method
    return performMethodInvocation(object, methodToInvoke, arguments);
  }

  /**
   * Invoke a private or inner class method. This might be useful to test
   * private methods.
   *
   */
  public static synchronized Object invokeMethod(Class<?> clazz, String methodToExecute, Object... arguments)
      throws Exception {
    return doInvokeMethod(clazz, null, methodToExecute, arguments);
  }

  private static Object doInvokeMethod(Object tested, Class<?> declaringClass, String methodToExecute,
      Object... arguments) throws Exception {
    Method methodToInvoke = findMethodOrThrowException(tested, declaringClass, methodToExecute, arguments);

    // Invoke test
    return performMethodInvocation(tested, methodToInvoke, arguments);
  }

  /**
   * Finds and returns a certain method. If the method couldn't be found this
   * method delegates to
   * {@link WhiteboxImpl#throwExceptionIfMethodWasNotFound(Object, String, Method, Object...)}
   * .
   *
   * @param tested
   *            The instance or class containing the method.
   * @param declaringClass
   *            The class where the method is supposed to be declared (may be
   *            <code>null</code>).
   * @param methodToExecute
   *            The method name. If <code>null</code> then method will be
   *            looked up based on the argument types only.
   * @param arguments
   *            The arguments of the methods.
   * @return A single method.
   */
  public static Method findMethodOrThrowException(Object tested, Class<?> declaringClass, String methodToExecute,
      Object... arguments) {

    if (tested == null) {
      throw new IllegalArgumentException("The object to perform the operation on cannot be null.");
    }

    /*
     * Get methods from the type if it's not mocked or from the super type
     * if the tested object is mocked.
     */
    Class<?> testedType = null;
    if (isClass(tested)) {
      testedType = (Class<?>) tested;
    } else {
      testedType = tested.getClass();
    }

    Method[] methods = null;
    if (declaringClass == null) {
      methods = getAllMethods(testedType);
    } else {
      methods = declaringClass.getDeclaredMethods();
    }
    Method potentialMethodToInvoke = null;
    for (Method method : methods) {
      if (methodToExecute == null || method.getName().equals(methodToExecute)) {
        Class<?>[] paramTypes = method.getParameterTypes();
        if ((arguments != null && (paramTypes.length == arguments.length))) {
          if (paramTypes.length == 0) {
            potentialMethodToInvoke = method;
            break;
          }
          boolean wrappedMethodFound = true;
          boolean primitiveMethodFound = true;
          if (!checkIfTypesAreSame(paramTypes, arguments)) {
            wrappedMethodFound = false;
          }

          if (!checkIfTypesAreSame(paramTypes, convertArgumentTypesToPrimitive(paramTypes, arguments))) {
            primitiveMethodFound = false;
          }

          if (wrappedMethodFound || primitiveMethodFound) {
            if (potentialMethodToInvoke == null) {
              potentialMethodToInvoke = method;
            } else {
              /*
               * We've already found a method match before, this
               * means that PowerMock cannot determine which
               * method to expect since there are two methods with
               * the same name and the same number of arguments
               * but one is using wrapper types.
               */
              throwExceptionWhenMultipleMethodMatchesFound("argument parameter types", new Method[] {
                  potentialMethodToInvoke, method });
            }
          }
        } else if (method.isVarArgs() && areAllArgumentsOfSameType(arguments)) {
          potentialMethodToInvoke = method;
          break;
        } else if (arguments != null && (paramTypes.length != arguments.length)) {
          continue;
        }
      }
    }

    WhiteboxImpl.throwExceptionIfMethodWasNotFound(getType(tested), methodToExecute, potentialMethodToInvoke,
        arguments);
    return potentialMethodToInvoke;
  }

/**
   * Finds and returns a certain constructor. If the constructor couldn't be
   * found this method delegates to
   * {@link Whitebox#throwExceptionIfConstructorWasNotFound(Class, Object...).
   *
   * @param type The type where the constructor should be located.
   * @param arguments The arguments passed to the constructor.
    * @return The found constructor.
    * @throws TooManyConstructorsFoundException If too many constructors matched.
    * @throws ConstructorNotFoundException If no constructor matched.
   */
  public static Constructor<?> findConstructorOrThrowException(Class<?> type, Object... arguments) {
    if (type == null) {
      throw new IllegalArgumentException("Class type cannot be null.");
    }

    Class<?> unmockedType = getUnmockedType(type);
    if ((unmockedType.isLocalClass() || unmockedType.isAnonymousClass() || unmockedType.isMemberClass())
        && !Modifier.isStatic(unmockedType.getModifiers()) && arguments != null) {
      Object[] argumentsForLocalClass = new Object[arguments.length + 1];
      argumentsForLocalClass[0] = unmockedType.getEnclosingClass();
      System.arraycopy(arguments, 0, argumentsForLocalClass, 1, arguments.length);
      arguments = argumentsForLocalClass;
    }

    Constructor<?>[] constructors = unmockedType.getDeclaredConstructors();
    Constructor<?> potentialConstructor = null;
    for (Constructor<?> constructor : constructors) {
      Class<?>[] paramTypes = constructor.getParameterTypes();
      if ((arguments != null && (paramTypes.length == arguments.length))) {
        if (paramTypes.length == 0) {
          potentialConstructor = constructor;
          break;
        }
        boolean wrappedConstructorFound = true;
        boolean primitiveConstructorFound = true;
        if (!checkIfTypesAreSame(paramTypes, arguments)) {
          wrappedConstructorFound = false;
        }

        if (!checkIfTypesAreSame(paramTypes, convertArgumentTypesToPrimitive(paramTypes, arguments))) {
          primitiveConstructorFound = false;
        }

        if (wrappedConstructorFound || primitiveConstructorFound) {
          if (potentialConstructor == null) {
            potentialConstructor = constructor;
          } else {
            /*
             * We've already found a constructor match before, this
             * means that PowerMock cannot determine which method to
             * expect since+ there are two methods with the same
             * name and the same number of arguments but one is
             * using wrapper types.
             */
            throwExceptionWhenMultipleConstructorMatchesFound(new Constructor<?>[] { potentialConstructor,
                constructor });
          }
        }
      } else if (constructor.isVarArgs() && areAllArgumentsOfSameType(arguments)) {
        potentialConstructor = constructor;
        break;
      } else if (arguments != null && (paramTypes.length != arguments.length)) {
        continue;
      }
    }

    WhiteboxImpl.throwExceptionIfConstructorWasNotFound(type, potentialConstructor, arguments);
    return potentialConstructor;
  }

  private static Class<?>[] convertArgumentTypesToPrimitive(Class<?>[] paramTypes, Object[] arguments) {
    Class<?>[] types = new Class<?>[arguments.length];
    for (int i = 0; i < arguments.length; i++) {
      Class<?> argumentType = null;
      if (arguments[i] == null) {
        argumentType = paramTypes[i];
      } else {
        argumentType = getType(arguments[i]);
      }
      Class<?> primitiveWrapperType = PrimitiveWrapper.getPrimitiveFromWrapperType(argumentType);
      if (primitiveWrapperType == null) {
        types[i] = argumentType;
      } else {
        types[i] = primitiveWrapperType;
      }
    }
    return types;
  }

  public static void throwExceptionIfMethodWasNotFound(Class<?> type, String methodName, Method methodToMock,
      Object... arguments) {
    if (methodToMock == null) {
      String methodNameData = "";
      if (methodName != null) {
        methodNameData = "with name '" + methodName + "' ";
      }
      throw new MethodNotFoundException("No method found " + methodNameData + "with argument types: [ "
          + getArgumentsAsString(arguments) + " ] in class " + getUnmockedType(type).getName());
    }
  }

  public static void throwExceptionIfFieldWasNotFound(Class<?> type, String fieldName, Field field) {
    if (field == null) {
      throw new FieldNotFoundException("No field was found with name '" + fieldName + "' in class "
          + getUnmockedType(type).getName());
    }
  }

  static void throwExceptionIfConstructorWasNotFound(Class<?> type, Constructor<?> potentialConstructor,
      Object... arguments) {
    if (potentialConstructor == null) {
      throw new ConstructorNotFoundException("No constructor found in class '" + getUnmockedType(type).getName()
          + "' with argument types: [ " + getArgumentsAsString(arguments) + " ]");
    }
  }

  private static String getArgumentsAsString(Object... arguments) {
    StringBuilder argumentsAsString = new StringBuilder();
    if (arguments != null && arguments.length != 0) {
      for (int i = 0; i < arguments.length; i++) {
        String argumentName = null;
        Object argument = arguments[i];

        if (argument instanceof Class) {
          argumentName = ((Class<?>) argument).getName();
        } else if (argument == null) {
          argumentName = "null";
        } else {
          argumentName = getType(argument).getName();
        }

        argumentsAsString.append(argumentName);
        if (i != arguments.length - 1) {
          argumentsAsString.append(", ");
        }
      }
    }
    return argumentsAsString.toString();
  }

  /**
   * Invoke a constructor. Useful for testing classes with a private
   * constructor when PowerMock cannot determine which constructor to invoke.
   * This only happens if you have two constructors with the same number of
   * arguments where one is using primitive data types and the other is using
   * the wrapped counter part. For example:
   *
   * <pre>
   * public class MyClass {
   *     private MyClass(Integer i) {
   *         ...
   *     }
   *
   *     private MyClass(int i) {
   *         ...
   *     }
   * </pre>
   *
   * This ought to be a really rare case. So for most situation, use
   * {@link #invokeConstructor(Class, Object...)} instead.
   *
   *
   * @return The object created after the constructor has been invoked.
   * @throws Exception
   *             If an exception occur when invoking the constructor.
   */
  public static <T> T invokeConstructor(Class<T> classThatContainsTheConstructorToTest, Class<?>[] parameterTypes,
      Object[] arguments) throws Exception {
    if (parameterTypes != null && arguments != null) {
      if (parameterTypes.length != arguments.length) {
        throw new IllegalArgumentException("parameterTypes and arguments must have the same length");
      }
    }

    Constructor<T> constructor = null;
    try {
      constructor = classThatContainsTheConstructorToTest.getDeclaredConstructor(parameterTypes);
    } catch (Exception e) {
      throw new ConstructorNotFoundException("Could not lookup the constructor", e);
    }

    return createInstance(constructor, arguments);
  }

  /**
   * Invoke a constructor. Useful for testing classes with a private
   * constructor.
   *
   *
   * @return The object created after the constructor has been invoked.
   * @throws Exception
   *             If an exception occur when invoking the constructor.
   */
  public static <T> T invokeConstructor(Class<T> classThatContainsTheConstructorToTest, Object... arguments)
      throws Exception {

    if (classThatContainsTheConstructorToTest == null) {
      throw new IllegalArgumentException("The class should contain the constructor cannot be null.");
    }

    Class<?>[] argumentTypes = null;
    if (arguments == null) {
      argumentTypes = new Class<?>[0];
    } else {
      argumentTypes = new Class<?>[arguments.length];
      for (int i = 0; i < arguments.length; i++) {
        argumentTypes[i] = getType(arguments[i]);
      }
    }

    Constructor<T> constructor = null;

    Constructor<T> potentialContstructorWrapped = null;
    Constructor<T> potentialContstructorPrimitive = null;

    try {
      potentialContstructorWrapped = classThatContainsTheConstructorToTest.getDeclaredConstructor(argumentTypes);
    } catch (Exception e) {
      // Do nothing, we'll try with primitive type next.
    }

    try {
      potentialContstructorPrimitive = classThatContainsTheConstructorToTest
          .getDeclaredConstructor(PrimitiveWrapper.toPrimitiveType(argumentTypes));
    } catch (Exception e) {
      // Do nothing
    }

    if (potentialContstructorPrimitive == null && potentialContstructorWrapped == null) {
      // Check if we can find a matching var args constructor.
      constructor = getPotentialVarArgsConstructor(classThatContainsTheConstructorToTest, arguments);
      if (constructor == null) {
        throw new ConstructorNotFoundException("Failed to find a constructor with argument types: ["
            + getArgumentsAsString(arguments) + "]");
      }
    } else if (potentialContstructorPrimitive == null && potentialContstructorWrapped != null) {
      constructor = potentialContstructorWrapped;
    } else if (potentialContstructorPrimitive != null && potentialContstructorWrapped == null) {
      constructor = potentialContstructorPrimitive;
    } else if (arguments == null || arguments.length == 0 && potentialContstructorPrimitive != null) {
      constructor = potentialContstructorPrimitive;
    } else {
      throw new TooManyConstructorsFoundException(
          "Could not determine which constructor to execute. Please specify the parameter types by hand.");
    }

    return createInstance(constructor, arguments);
  }

  @SuppressWarnings("unchecked")
  private static <T> Constructor<T> getPotentialVarArgsConstructor(Class<T> classThatContainsTheConstructorToTest,
      Object... arguments) {
    if (areAllArgumentsOfSameType(arguments)) {
      Constructor<T>[] declaredConstructors = (Constructor<T>[]) classThatContainsTheConstructorToTest
          .getDeclaredConstructors();
      for (Constructor<T> possibleVarArgsConstructor : declaredConstructors) {
        if (possibleVarArgsConstructor.isVarArgs()) {
          if (arguments == null || arguments.length == 0) {
            return possibleVarArgsConstructor;
          } else if (possibleVarArgsConstructor.getParameterTypes()[0].getComponentType().isAssignableFrom(
              getType(arguments[0]))) {
            return possibleVarArgsConstructor;
          }
        }
      }
    }
    return null;
  }

  private static <T> T createInstance(Constructor<T> constructor, Object... arguments) throws Exception {
    if (constructor == null) {
      throw new IllegalArgumentException("Constructor cannot be null");
    }
    constructor.setAccessible(true);

    T createdObject = null;
    try {
      if (constructor.isVarArgs()) {
        Class<?> varArgsType = constructor.getParameterTypes()[0].getComponentType();
        Object arrayInstance = createAndPopulateArray(varArgsType, arguments);
        createdObject = constructor.newInstance(new Object[] { arrayInstance });
      } else {
        createdObject = constructor.newInstance(arguments);
      }
    } catch (InvocationTargetException e) {
      Throwable cause = e.getCause();
      if (cause instanceof Exception) {
        throw (Exception) cause;
      } else if (cause instanceof Error) {
        throw (Error) cause;
      }
    }
    return createdObject;
  }

  private static Object createAndPopulateArray(Class<?> varArgsType, Object... arguments) {
    Object arrayInstance = Array.newInstance(varArgsType, arguments.length);
    for (int i = 0; i < arguments.length; i++) {
      Array.set(arrayInstance, i, arguments[i]);
    }
    return arrayInstance;
  }

  /**
   * Get all methods in a class hierarchy! Both declared an non-declared (no
   * duplicates).
   *
   * @param clazz
   *            The class whose methods to get.
   * @return All methods declared in this class hierarchy.
   */
  private static Method[] getAllMethods(Class<?> clazz) {
    if (clazz == null) {
      throw new IllegalArgumentException("You must specify a class in order to get the methods.");
    }
    Set<Method> methods = new LinkedHashSet<Method>();

    Class<?> thisType = clazz;

    while (thisType != null) {
      final Class<?> type = thisType;
      final Method[] declaredMethods = AccessController.doPrivileged(new PrivilegedAction<Method[]>() {

        public Method[] run() {
          return type.getDeclaredMethods();
        }

      });
      for (Method method : declaredMethods) {
        method.setAccessible(true);
        methods.add(method);
      }
      thisType = thisType.getSuperclass();
    }
    return methods.toArray(new Method[0]);
  }

  /**
   * Get all public methods for a class (no duplicates)! Note that the
   * class-hierarchy will not be traversed.
   *
   * @param clazz
   *            The class whose methods to get.
   * @return All public methods declared in <tt>this</tt> class.
   */
  private static Method[] getAllPublicMethods(Class<?> clazz) {
    if (clazz == null) {
      throw new IllegalArgumentException("You must specify a class in order to get the methods.");
    }
    Set<Method> methods = new LinkedHashSet<Method>();

    for (Method method : clazz.getMethods()) {
      method.setAccessible(true);
      methods.add(method);
    }
    return methods.toArray(new Method[0]);
  }

  /**
   * Get all fields in a class hierarchy! Both declared an non-declared (no
   * duplicates).
   *
   * @param clazz
   *            The class whose fields to get.
   * @return All fields declared in this class hierarchy.
   */
  private static Field[] getAllFields(Class<?> clazz) {
    if (clazz == null) {
      throw new IllegalArgumentException("You must specify the class that contains the fields");
    }
    Set<Field> fields = new LinkedHashSet<Field>();

    Class<?> thisType = clazz;

    while (thisType != null) {
      final Field[] declaredFields = thisType.getDeclaredFields();
      for (Field field : declaredFields) {
        field.setAccessible(true);
        fields.add(field);
      }
      thisType = thisType.getSuperclass();
    }
    return fields.toArray(new Field[fields.size()]);
  }

  /**
   * Get the first parent constructor defined in a super class of
   * <code>klass</code>.
   *
   * @param klass
   *            The class where the constructor is located. <code>null</code>
   *            ).
   * @return A <code>java.lang.reflect.Constructor</code>.
   */
  public static Constructor<?> getFirstParentConstructor(Class<?> klass) {

    try {
      return getUnmockedType(klass).getSuperclass().getDeclaredConstructors()[0];
    } catch (Exception e) {
      throw new ConstructorNotFoundException("Failed to lookup constructor.", e);
    }
  }

  /**
   * Finds and returns a method based on the input parameters. If no
   * <code>parameterTypes</code> are present the method will return the first
   * method with name <code>methodNameToMock</code>. If no method was found,
   * <code>null</code> will be returned. If no <code>methodName</code> is
   * specified the method will be found based on the parameter types. If
   * neither method name nor parameters are specified an
   * {@link IllegalArgumentException} will be thrown.
   *
   * @param <T>
   * @param type
   * @param methodName
   * @param parameterTypes
   * @return
   */
  static <T> Method findMethod(Class<T> type, String methodName, Class<?>... parameterTypes) {
    if (methodName == null && parameterTypes == null) {
      throw new IllegalArgumentException("You must specify a method name or parameter types.");
    }
    List<Method> matchingMethodsList = new LinkedList<Method>();
    for (Method method : getAllMethods(type)) {
      if (methodName == null || method.getName().equals(methodName)) {
        if (parameterTypes != null && parameterTypes.length > 0) {
          // If argument types was supplied, make sure that they
          // match.
          Class<?>[] paramTypes = method.getParameterTypes();
          if (!checkIfTypesAreSame(parameterTypes, paramTypes)) {
            continue;
          }
        }
        // Add the method to the matching methods list.
        matchingMethodsList.add(method);
      }
    }

    Method methodToMock = null;
    if (matchingMethodsList.size() > 0) {
      if (matchingMethodsList.size() == 1) {
        // We've found a unique method match.
        methodToMock = matchingMethodsList.get(0);
      } else if (parameterTypes.length == 0) {
        /*
         * If we've found several matches and we've supplied no
         * parameter types, go through the list of found methods and see
         * if we have a method with no parameters. In that case return
         * that method.
         */
        for (Method method : matchingMethodsList) {
          if (method.getParameterTypes().length == 0) {
            methodToMock = method;
            break;
          }
        }

        if (methodToMock == null) {
          WhiteboxImpl.throwExceptionWhenMultipleMethodMatchesFound("argument parameter types",
              matchingMethodsList.toArray(new Method[0]));
        }
      } else {
        // We've found several matching methods.
        WhiteboxImpl.throwExceptionWhenMultipleMethodMatchesFound("argument parameter types",
            matchingMethodsList.toArray(new Method[0]));
      }
    }

    return methodToMock;
  }

  public static <T> Class<?> getUnmockedType(Class<T> type) {
    if (type == null) {
      throw new IllegalArgumentException("type cannot be null");
    }

    Class<?> unmockedType = null;
    if (proxyFramework != null && proxyFramework.isProxy(type)) {
      unmockedType = proxyFramework.getUnproxiedType(type);
    } else if (Proxy.isProxyClass(type)) {
      unmockedType = type.getInterfaces()[0];
    } else {
      unmockedType = type;
    }
    return unmockedType;
  }

  static void throwExceptionWhenMultipleMethodMatchesFound(String helpInfo, Method[] methods) {
    if (methods == null || methods.length < 2) {
      throw new IllegalArgumentException(
          "Internal error: throwExceptionWhenMultipleMethodMatchesFound needs at least two methods.");
    }
    StringBuilder sb = new StringBuilder();
    sb.append("Several matching methods found, please specify the ");
    sb.append(helpInfo);
    sb.append(" so that PowerMock can determine which method you're refering to.\n");
    sb.append("Matching methods in class ").append(methods[0].getDeclaringClass().getName()).append(" were:\n");

    for (Method method : methods) {
      sb.append(method.getReturnType().getName()).append(" ");
      sb.append(method.getName()).append("( ");
      final Class<?>[] parameterTypes = method.getParameterTypes();
      for (Class<?> paramType : parameterTypes) {
        sb.append(paramType.getName()).append(".class ");
      }
      sb.append(")\n");
    }
    throw new TooManyMethodsFoundException(sb.toString());
  }

  static void throwExceptionWhenMultipleConstructorMatchesFound(Constructor<?>[] constructors) {
    if (constructors == null || constructors.length < 2) {
      throw new IllegalArgumentException(
          "Internal error: throwExceptionWhenMultipleMethodMatchesFound needs at least two methods.");
    }
    StringBuilder sb = new StringBuilder();
    sb
        .append("Several matching constructors found, please specify the argument parameter types so that PowerMock can determine which method you're refering to.\n");
    sb.append("Matching constructors in class ").append(constructors[0].getDeclaringClass().getName()).append(
        " were:\n");

    for (Constructor<?> constructor : constructors) {
      sb.append(constructor.getName()).append("( ");
      final Class<?>[] parameterTypes = constructor.getParameterTypes();
      for (Class<?> paramType : parameterTypes) {
        sb.append(paramType.getName()).append(".class ");
      }
      sb.append(")\n");
    }
    throw new TooManyConstructorsFoundException(sb.toString());
  }

  @SuppressWarnings("all")
  public static Method findMethodOrThrowException(Class<?> type, String methodName, Class<?>... parameterTypes) {
    Method methodToMock = findMethod(type, methodName, parameterTypes);
    throwExceptionIfMethodWasNotFound(type, methodName, methodToMock, parameterTypes);
    return methodToMock;
  }

  /**
   * Get an array of {@link Method}'s that matches the supplied list of method
   * names. Both instance and static methods are taken into account.
   *
   * @param clazz
   *            The class that should contain the methods.
   * @param methodNames
   *            Names of the methods that will be returned.
   * @return An array of Method's. May be of length 0 but not
   *         <code>null</code>.
   * @throws MethodNotFoundException
   *             If no method was found.
   */
  public static Method[] getMethods(Class<?> clazz, String... methodNames) {
    if (methodNames == null || methodNames.length == 0) {
      throw new IllegalArgumentException("You must supply at least one method name.");
    }
    final List<Method> methodsToMock = new LinkedList<Method>();
    Method[] allMethods = null;
    if (clazz.isInterface()) {
      allMethods = getAllPublicMethods(clazz);
    } else {
      allMethods = getAllMethods(clazz);
    }

    for (Method method : allMethods) {
      for (String methodName : methodNames) {
        if (method.getName().equals(methodName)) {
          method.setAccessible(true);
          methodsToMock.add(method);
        }
      }
    }

    final Method[] methodArray = methodsToMock.toArray(new Method[0]);
    if (methodArray.length == 0) {
      throw new MethodNotFoundException(String.format(
          "No methods matching the name(s) %s were found in the class hierarchy of %s.",
          concatenateStrings(methodNames), getType(clazz)));
    }
    return methodArray;
  }

  /**
   * Get an array of {@link Field}'s that matches the supplied list of field
   * names. Both instance and static fields are taken into account.
   *
   * @param clazz
   *            The class that should contain the fields.
   * @param fieldNames
   *            Names of the fields that will be returned.
   * @return An array of Field's. May be of length 0 but not <code>null</code>
   *         .
   */
  public static Field[] getFields(Class<?> clazz, String... fieldNames) {
    final List<Field> fields = new LinkedList<Field>();

    for (Field field : getAllFields(clazz)) {
      for (String fieldName : fieldNames) {
        if (field.getName().equals(fieldName)) {
          fields.add(field);
        }
      }
    }

    final Field[] fieldArray = fields.toArray(new Field[fields.size()]);
    if (fieldArray.length == 0) {
      throw new FieldNotFoundException(String.format(
          "No fields matching the name(s) %s were found in the class hierarchy of %s.",
          concatenateStrings(fieldNames), getType(clazz)));
    }
    return fieldArray;
  }

  public static Object performMethodInvocation(Object tested, Method methodToInvoke, Object... arguments)
      throws Exception {
    methodToInvoke.setAccessible(true);
    try {
      if (methodToInvoke.isVarArgs()) {
        Class<?> arrayType = methodToInvoke.getParameterTypes()[0].getComponentType();
        Object arrayInstance = createAndPopulateArray(arrayType, arguments);
        return methodToInvoke.invoke(tested, new Object[] { arrayInstance });
      } else {
        return methodToInvoke.invoke(tested, arguments == null ? new Object[] { arguments } : arguments);
      }
    } catch (InvocationTargetException e) {
      Throwable cause = e.getCause();
      if (cause instanceof Exception) {
        throw (Exception) cause;
      } else if (cause instanceof Error) {
        throw (Error) cause;
      } else {
        throw new MethodInvocationException(cause);
      }
    } catch (Exception e) {
      if (e instanceof InvocationTargetException) {
        Throwable cause = e.getCause();
        if (cause instanceof Exception) {
          throw (Exception) cause;
        } else {
          throw new MethodInvocationException("Failed to invoke method " + methodToInvoke.getName()
              + " on object " + tested + ". Reason was \"" + e.getMessage() + "\".", e);
        }
      } else {
        throw e;
      }
    }
  }

  public static <T> Method[] getAllMethodExcept(Class<T> type, String... methodNames) {
    List<Method> methodsToMock = new LinkedList<Method>();
    Method[] methods = getAllMethods(type);
    iterateMethods: for (Method method : methods) {
      for (String methodName : methodNames) {
        if (method.getName().equals(methodName)) {
          continue iterateMethods;
        }
      }
      methodsToMock.add(method);
    }
    return methodsToMock.toArray(new Method[0]);
  }

  public static <T> Method[] getAllMetodsExcept(Class<T> type, String methodNameToExclude, Class<?>[] argumentTypes) {
    Method[] methods = getAllMethods(type);
    List<Method> methodList = new ArrayList<Method>();
    outer: for (Method method : methods) {
      if (method.getName().equals(methodNameToExclude)) {
        if (argumentTypes != null && argumentTypes.length > 0) {
          final Class<?>[] args = method.getParameterTypes();
          if (args != null && args.length == argumentTypes.length) {
            for (int i = 0; i < args.length; i++) {
              if (args[i].isAssignableFrom(getUnmockedType(argumentTypes[i]))) {
                /*
                 * Method was not found thus it should not be
                 * mocked. Continue to investigate the next
                 * method.
                 */
                continue outer;
              }
            }
          }
        } else {
          continue;
        }
      }
      methodList.add(method);
    }
    return methodList.toArray(new Method[0]);
  }

  public static boolean areAllMethodsStatic(Method... methods) {
    for (Method method : methods) {
      if (!Modifier.isStatic(method.getModifiers())) {
        return false;
      }
    }
    return true;
  }

  /**
   * Check if all arguments are of the same type.
   */
  static boolean areAllArgumentsOfSameType(Object[] arguments) {
    if (arguments == null || arguments.length <= 1) {
      return true;
    }

    // Handle null values
    int index = 0;
    Object object = null;
    while (object == null && index < arguments.length) {
      object = arguments[index++];
    }

    if (object == null) {
      return true;
    }
    // End of handling null values

    final Class<?> firstArgumentType = getType(object);
    for (int i = index; i < arguments.length; i++) {
      final Object argument = arguments[i];
      if (argument != null && !getType(argument).isAssignableFrom(firstArgumentType)) {
        return false;
      }
    }

    return true;
  }

  /**
   * @return <code>true</code> if all actual parameter types are assignable
   *         from the expected arguments, <code>false</code> otherwise.
   */
  private static boolean checkIfTypesAreSame(Class<?>[] parameterTypes, Object[] arguments) {
    if (parameterTypes == null) {
      throw new IllegalArgumentException("parameter types cannot be null");
    } else if (parameterTypes.length != arguments.length) {
      return false;
    }
    for (int i = 0; i < parameterTypes.length; i++) {
      Object argument = arguments[i];
      if (argument == null) {
        continue;
      } else {
        if (!parameterTypes[i].isAssignableFrom(getType(argument))
            && !(parameterTypes[i].equals(Class.class) && isClass(argument))) {
          return false;
        }
      }
    }
    return true;
  }

  /**
   * @return The type of the of an object.
   */
  public static Class<?> getType(Object object) {
    Class<?> type = null;
    if (isClass(object)) {
      type = (Class<?>) object;
    } else if (object != null) {
      type = object.getClass();
    }
    return getUnmockedType(type);
  }

  /**
   * Get an inner class type
   *
   * @param declaringClass
   *            The class in which the inner class is declared.
   * @param name
   *            The unqualified name (simple name) of the inner class.
   * @return The type.
   */
  @SuppressWarnings("unchecked")
  public static Class<Object> getInnerClassType(Class<?> declaringClass, String name) throws ClassNotFoundException {
    return (Class<Object>) Class.forName(declaringClass.getName() + "$" + name);
  }

  /**
   * Get the type of a local inner class.
   *
   * @param declaringClass
   *            The class in which the local inner class is declared.
   * @param occurrence
   *            The occurrence of the local class. For example if you have two
   *            local classes in the <code>declaringClass</code> you must pass
   *            in <code>1</code> if you want to get the type for the first
   *            one or <code>2</code> if you want the second one.
   * @param name
   *            The unqualified name (simple name) of the local class.
   * @return The type.
   */
  @SuppressWarnings("unchecked")
  public static Class<Object> getLocalClassType(Class<?> declaringClass, int occurrence, String name)
      throws ClassNotFoundException {
    return (Class<Object>) Class.forName(declaringClass.getName() + "$" + occurrence + name);
  }

  /**
   * Get the type of an anonymous inner class.
   *
   * @param declaringClass
   *            The class in which the anonymous inner class is declared.
   * @param occurrence
   *            The occurrence of the anonymous inner class. For example if
   *            you have two anonymous inner classes classes in the
   *            <code>declaringClass</code> you must pass in <code>1</code> if
   *            you want to get the type for the first one or <code>2</code>
   *            if you want the second one.
   * @return The type.
   */
  @SuppressWarnings("unchecked")
  public static Class<Object> getAnonymousInnerClassType(Class<?> declaringClass, int occurrence)
      throws ClassNotFoundException {
    return (Class<Object>) Class.forName(declaringClass.getName() + "$" + occurrence);
  }

  /**
   * Get all fields annotated with a particular annotation. This method
   * traverses the class hierarchy when checking for the annotation.
   *
   * @param object
   *            The object to look for annotations. Note that if're you're
   *            passing an object only instance fields are checked, passing a
   *            class will only check static fields.
   * @param annotation
   *            The annotation type to look for.
   * @param additionalAnnotations
   *            Optionally more annotations to look for. If any of the
   *            annotations are associated with a particular field it will be
   *            added to the resulting <code>Set</code>.
   * @return A set of all fields containing the particular annotation.
   */
  @SuppressWarnings("unchecked")
  public static Set<Field> getFieldsAnnotatedWith(Object object, Class<? extends Annotation> annotation,
      Class<? extends Annotation>... additionalAnnotations) {
    Class<? extends Annotation>[] annotations = null;
    if (additionalAnnotations == null || additionalAnnotations.length == 0) {
      annotations = (Class<? extends Annotation>[]) new Class<?>[] { annotation };
    } else {
      annotations = (Class<? extends Annotation>[]) new Class<?>[additionalAnnotations.length + 1];
      annotations[0] = annotation;
      System.arraycopy(additionalAnnotations, 0, annotations, 1, additionalAnnotations.length);
    }

    return findAllFieldsUsingStrategy(new FieldAnnotationMatcherStrategy(annotations), object, true,
        getType(object));
  }

  /**
   * Get all fields assignable from a particular type. This method traverses
   * the class hierarchy when checking for the type.
   *
   * @param object
   *            The object to look for type. Note that if're you're passing an
   *            object only instance fields are checked, passing a class will
   *            only check static fields.
   * @param type
   *            The type to look for.
   * @return A set of all fields of the particular type.
   */
  public static Set<Field> getFieldsOfType(Object object, Class<?> type) {
    return findAllFieldsUsingStrategy(new AssignableToFieldTypeMatcherStrategy(type), object, true, getType(object));
  }

  /**
   * Get all instance fields for a particular object. It returns all fields
   * regardless of the field modifier and regardless of where in the class
   * hierarchy a field is located.
   *
   * @param object
   *            The object whose instance fields to get.
   * @return All instance fields in the hierarchy. All fields are set to
   *         accessible
   */
  public static Set<Field> getAllInstanceFields(Object object) {
    return findAllFieldsUsingStrategy(new AllFieldsMatcherStrategy(), object, true, getType(object));
  }

  /**
   * Get all static fields for a particular type.
   *
   * @param type
   *            The class whose static fields to get.
   * @return All static fields in <code>type</code>. All fields are set to
   *         accessible.
   */
  public static Set<Field> getAllStaticFields(Class<?> type) {
    final Set<Field> fields = new LinkedHashSet<Field>();
    final Field[] declaredFields = type.getDeclaredFields();
    for (Field field : declaredFields) {
      if (Modifier.isStatic(field.getModifiers())) {
        field.setAccessible(true);
        fields.add(field);
      }
    }
    return fields;
  }

  private static boolean isClass(Object argument) {
    return argument instanceof Class<?>;
  }

  /**
   * @return <code>true</code> if all actual parameter types are assignable
   *         from the expected parameter types, <code>false</code> otherwise.
   */
  private static boolean checkIfTypesAreSame(Class<?>[] expectedParameterTypes, Class<?>[] actualParameterTypes) {
    if (expectedParameterTypes == null || actualParameterTypes == null) {
      throw new IllegalArgumentException("parameter types cannot be null");
    } else if (expectedParameterTypes.length != actualParameterTypes.length) {
      return false;
    } else {
      for (int i = 0; i < expectedParameterTypes.length; i++) {
        if (!expectedParameterTypes[i].isAssignableFrom(getType(actualParameterTypes[i]))) {
          return false;
        }
      }
    }
    return true;
  }

  private static Field getField(String fieldName, Class<?> where) {
    if (where == null) {
      throw new IllegalArgumentException("where cannot be null");
    }

    Field field = null;
    try {
      field = where.getDeclaredField(fieldName);
      field.setAccessible(true);
    } catch (NoSuchFieldException e) {
      throw new FieldNotFoundException("Field '" + fieldName + "' was not found in class " + where.getName()
          + ".");
    }
    return field;
  }

  private static Field findFieldOrThrowException(Class<?> fieldType, Class<?> where) {
    if (fieldType == null || where == null) {
      throw new IllegalArgumentException("fieldType and where cannot be null");
    }
    Field field = null;
    for (Field currentField : where.getDeclaredFields()) {
      currentField.setAccessible(true);
      if (currentField.getType().equals(fieldType)) {
        field = currentField;
        break;
      }
    }
    if (field == null) {
      throw new FieldNotFoundException("Cannot find a field of type " + fieldType + "in where.");
    }
    return field;
  }

  private static void setField(Object object, Object value, Field foundField) {
    foundField.setAccessible(true);
    try {
      foundField.set(object, value);
    } catch (IllegalAccessException e) {
      throw new RuntimeException("Internal error: Failed to set field in method setInternalState.", e);
    }
  }

  private static String concatenateStrings(String... stringsToConcatenate) {
    StringBuilder builder = new StringBuilder();
    final int stringsLength = stringsToConcatenate.length;
    for (int i = 0; i < stringsLength; i++) {
      if (i == stringsLength - 1 && stringsLength != 1) {
        builder.append(" or ");
      } else if (i != 0) {
        builder.append(", ");
      }
      builder.append(stringsToConcatenate[i]);
    }
    return builder.toString();
  }
}
TOP

Related Classes of org.powermock.reflect.internal.WhiteboxImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.