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

mockit.internal.util.MethodReflection Maven / Gradle / Ivy

Go to download

JMockit is a Java toolkit for automated developer testing. It contains APIs for the creation of the objects to be tested, for mocking dependencies, and for faking external APIs; JUnit (4 & 5) and TestNG test runners are supported. It also contains an advanced code coverage tool.

There is a newer version: 1.49
Show newest version
/*
 * Copyright (c) 2006 Rogério Liesenfeld
 * This file is subject to the terms of the MIT license (see LICENSE.txt).
 */
package mockit.internal.util;

import java.lang.reflect.*;
import javax.annotation.*;
import static java.lang.reflect.Modifier.*;

import mockit.*;
import static mockit.internal.util.ParameterReflection.*;

public final class MethodReflection
{
   private MethodReflection() {}

   @Nullable
   public static  T invoke(
      @Nonnull Class theClass, @Nullable Object targetInstance, @Nonnull String methodName,
      @Nonnull Class[] paramTypes, @Nullable Object... methodArgs)
   {
      if (methodArgs == null) {
         throw invalidArguments();
      }

      Method method = findSpecifiedMethod(theClass, methodName, paramTypes);
      T result = invoke(targetInstance, method, methodArgs);
      return result;
   }

   @Nonnull
   private static Method findSpecifiedMethod(
      @Nonnull Class theClass, @Nonnull String methodName, @Nonnull Class[] paramTypes)
   {
      while (true) {
         for (Method declaredMethod : theClass.getDeclaredMethods()) {
            if (declaredMethod.getName().equals(methodName)) {
               Class[] declaredParameterTypes = declaredMethod.getParameterTypes();
               int firstRealParameter = indexOfFirstRealParameter(declaredParameterTypes, paramTypes);

               if (
                  firstRealParameter >= 0 &&
                     matchesParameterTypes(declaredMethod.getParameterTypes(), paramTypes, firstRealParameter)
                  ) {
                  return declaredMethod;
               }
            }
         }

         Class superClass = theClass.getSuperclass();

         if (superClass == null || superClass == Object.class) {
            String paramTypesDesc = getParameterTypesDescription(paramTypes);
            throw new IllegalArgumentException("Specified method not found: " + methodName + paramTypesDesc);
         }

         //noinspection AssignmentToMethodParameter
         theClass = superClass;
      }
   }

   @Nullable
   public static  T invokePublicIfAvailable(
      @Nonnull Class aClass, @Nullable Object targetInstance, @Nonnull String methodName,
      @Nonnull Class[] parameterTypes, @Nonnull Object... methodArgs)
   {
      Method publicMethod;
      try { publicMethod = aClass.getMethod(methodName, parameterTypes); }
      catch (NoSuchMethodException ignore) { return null; }

      T result = invoke(targetInstance, publicMethod, methodArgs);
      return result;
   }

   @Nullable
   public static  T invokeWithCheckedThrows(
      @Nonnull Class theClass, @Nullable Object targetInstance, @Nonnull String methodName,
      @Nonnull Class[] paramTypes, @Nonnull Object... methodArgs)
      throws Throwable
   {
      Method method = findSpecifiedMethod(theClass, methodName, paramTypes);
      T result = invokeWithCheckedThrows(targetInstance, method, methodArgs);
      return result;
   }

   @Nullable
   public static  T invoke(@Nullable Object targetInstance, @Nonnull Method method, @Nonnull Object... methodArgs)
   {
      Utilities.ensureThatMemberIsAccessible(method);

      try {
         //noinspection unchecked
         return (T) method.invoke(targetInstance, methodArgs);
      }
      catch (IllegalAccessException e) {
         throw new RuntimeException(e);
      }
      catch (IllegalArgumentException e) {
         StackTrace.filterStackTrace(e);
         throw new IllegalArgumentException("Failure to invoke method: " + method, e);
      }
      catch (InvocationTargetException e) {
         Throwable cause = e.getCause();

         if (cause instanceof Error) {
            throw (Error) cause;
         }
         else if (cause instanceof RuntimeException) {
            throw (RuntimeException) cause;
         }
         else {
            ThrowOfCheckedException.doThrow((Exception) cause);
            return null;
         }
      }
   }

   @Nullable
   public static  T invokeWithCheckedThrows(
      @Nullable Object targetInstance, @Nonnull Method method, @Nonnull Object... methodArgs)
      throws Throwable
   {
      Utilities.ensureThatMemberIsAccessible(method);

      try {
         //noinspection unchecked
         return (T) method.invoke(targetInstance, methodArgs);
      }
      catch (IllegalArgumentException e) {
         StackTrace.filterStackTrace(e);
         throw new IllegalArgumentException("Failure to invoke method: " + method, e);
      }
      catch (InvocationTargetException e) {
         throw e.getCause();
      }
   }

   @Nullable
   public static  T invoke(
      @Nonnull Class theClass, @Nullable Object targetInstance, @Nonnull String methodName,
      @Nullable Object... methodArgs)
   {
      if (methodArgs == null) {
         throw invalidArguments();
      }

      boolean staticMethod = targetInstance == null;
      Class[] argTypes = getArgumentTypesFromArgumentValues(methodArgs);
      Method method = staticMethod ?
         findCompatibleStaticMethod(theClass, methodName, argTypes) :
         findCompatibleMethod(theClass, methodName, argTypes);

      if (staticMethod && !isStatic(method.getModifiers())) {
         throw new IllegalArgumentException(
            "Attempted to invoke non-static method without an instance to invoke it on");
      }

      T result = invoke(targetInstance, method, methodArgs);
      return result;
   }

   @Nonnull
   private static Method findCompatibleStaticMethod(
      @Nonnull Class theClass, @Nonnull String methodName, @Nonnull Class[] argTypes)
   {
      Method methodFound = findCompatibleMethodInClass(theClass, methodName, argTypes);

      if (methodFound != null) {
         return methodFound;
      }

      String argTypesDesc = getParameterTypesDescription(argTypes);
      throw new IllegalArgumentException("No compatible static method found: " + methodName + argTypesDesc);
   }

   @Nonnull
   public static Method findCompatibleMethod(
      @Nonnull Class theClass, @Nonnull String methodName, @Nonnull Class[] argTypes)
   {
      Method methodFound = findCompatibleMethodIfAvailable(theClass, methodName, argTypes);

      if (methodFound != null) {
         return methodFound;
      }

      String argTypesDesc = getParameterTypesDescription(argTypes);
      throw new IllegalArgumentException("No compatible method found: " + methodName + argTypesDesc);
   }

   @Nullable
   private static Method findCompatibleMethodIfAvailable(
      @Nonnull Class theClass, @Nonnull String methodName, @Nonnull Class[] argTypes)
   {
      Method methodFound = null;

      while (true) {
         Method compatibleMethod = findCompatibleMethodInClass(theClass, methodName, argTypes);

         if (
            compatibleMethod != null &&
            (methodFound == null ||
             hasMoreSpecificTypes(compatibleMethod.getParameterTypes(), methodFound.getParameterTypes()))
         ) {
            methodFound = compatibleMethod;
         }

         Class superClass = theClass.getSuperclass();

         if (superClass == null || superClass == Object.class) {
            break;
         }

         //noinspection AssignmentToMethodParameter
         theClass = superClass;
      }

      return methodFound;
   }

   @Nullable
   private static Method findCompatibleMethodInClass(
      @Nonnull Class theClass, @Nonnull String methodName, @Nonnull Class[] argTypes)
   {
      Method found = null;
      Class[] foundParamTypes = null;

      for (Method declaredMethod : theClass.getDeclaredMethods()) {
         if (declaredMethod.getName().equals(methodName)) {
            Class[] declaredParamTypes = declaredMethod.getParameterTypes();
            int firstRealParameter = indexOfFirstRealParameter(declaredParamTypes, argTypes);

            if (
               firstRealParameter >= 0 &&
               (matchesParameterTypes(declaredParamTypes, argTypes, firstRealParameter) ||
                acceptsArgumentTypes(declaredParamTypes, argTypes, firstRealParameter)) &&
               (foundParamTypes == null || hasMoreSpecificTypes(declaredParamTypes, foundParamTypes))
            ) {
               found = declaredMethod;
               foundParamTypes = declaredParamTypes;
            }
         }
      }

      return found;
   }

   @Nonnull
   public static Method findNonPrivateHandlerMethod(@Nonnull Object handler)
   {
      Class handlerClass = handler.getClass();
      Method nonPrivateMethod;

      do {
         nonPrivateMethod = findNonPrivateHandlerMethod(handlerClass);

         if (nonPrivateMethod != null) {
            break;
         }

         handlerClass = handlerClass.getSuperclass();
      }
      while (handlerClass != null && handlerClass != Object.class);

      if (nonPrivateMethod == null) {
         throw new IllegalArgumentException("No non-private instance method found");
      }

      return nonPrivateMethod;
   }

   @Nullable
   private static Method findNonPrivateHandlerMethod(@Nonnull Class handlerClass)
   {
      Method[] declaredMethods = handlerClass.getDeclaredMethods();
      Method found = null;

      for (Method declaredMethod : declaredMethods) {
         int methodModifiers = declaredMethod.getModifiers();

         if (!isPrivate(methodModifiers) && !isStatic(methodModifiers)) {
            if (found != null) {
               String methodType = Delegate.class.isAssignableFrom(handlerClass) ? "delegate" : "invocation handler";
               throw new IllegalArgumentException(
                  "More than one candidate " + methodType + " method found: " +
                  methodSignature(found) + ", " + methodSignature(declaredMethod));
            }

            found = declaredMethod;
         }
      }

      return found;
   }

   @Nonnull
   private static String methodSignature(@Nonnull Method method)
   {
      String signature = method.toGenericString().replace("java.lang.", "");

      int p = signature.lastIndexOf('(');
      int q = signature.lastIndexOf('.', p);

      return signature.substring(q + 1);
   }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy