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

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

There is a newer version: 2.5.0
Show newest version
/*
 * Copyright (c) 2006-2012 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 static mockit.internal.util.ParameterReflection.*;

public final class ConstructorReflection
{
   public static  T newInstance(Class aClass, Class[] parameterTypes, Object... initArgs)
   {
      Constructor constructor = findSpecifiedConstructor(aClass, parameterTypes);
      return invoke(constructor, initArgs);
   }

   private static  Constructor findSpecifiedConstructor(Class theClass, Class[] paramTypes)
   {
      for (Constructor declaredConstructor : theClass.getDeclaredConstructors()) {
         Class[] declaredParameterTypes = declaredConstructor.getParameterTypes();
         int firstRealParameter = indexOfFirstRealParameter(declaredParameterTypes, paramTypes);

         if (
            firstRealParameter >= 0 &&
            matchesParameterTypes(declaredParameterTypes, paramTypes, firstRealParameter)
         ) {
            //noinspection unchecked
            return (Constructor) declaredConstructor;
         }
      }

      String paramTypesDesc = getParameterTypesDescription(paramTypes);

      throw new IllegalArgumentException(
         "Specified constructor not found: " + theClass.getSimpleName() + paramTypesDesc);
   }

   public static  T invoke(Constructor constructor, Object... initArgs)
   {
      Utilities.ensureThatMemberIsAccessible(constructor);

      Object[] args = initArgs != null? initArgs : getDefaultParameterValues(constructor);

      try {
         return constructor.newInstance(args);
      }
      catch (InstantiationException e) {
         throw new RuntimeException(e);
      }
      catch (IllegalAccessException e) {
         throw new RuntimeException(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;
         }
      }
   }

   private static Object[] getDefaultParameterValues(Constructor constructor)
   {
      Class[] parameterTypes = constructor.getParameterTypes();
      int numParameters = parameterTypes.length;
      Object[] defaultArgs = new Object[numParameters];

      for (int i = 0; i < numParameters; i++) {
         Class paramType = parameterTypes[i];
         defaultArgs[i] = DefaultValues.computeForType(paramType);
      }

      return defaultArgs;
   }

   public static  T newInstance(String className, Class[] parameterTypes, Object... initArgs)
   {
      Class theClass = ClassLoad.loadClass(className);
      return newInstance(theClass, parameterTypes, initArgs);
   }

   public static  T newInstance(String className, Object... nonNullArgs)
   {
      Class[] argTypes = getArgumentTypesFromArgumentValues(nonNullArgs);
      Class theClass = ClassLoad.loadClass(className);
      Constructor constructor = findCompatibleConstructor(theClass, argTypes);
      return invoke(constructor, nonNullArgs);
   }

   private static  Constructor findCompatibleConstructor(Class theClass, Class[] argTypes)
   {
      Constructor found = null;
      Class[] foundParameters = null;
      Constructor[] declaredConstructors = theClass.getDeclaredConstructors();

      for (Constructor declaredConstructor : declaredConstructors) {
         Class[] declaredParamTypes = declaredConstructor.getParameterTypes();
         int firstRealParameter = indexOfFirstRealParameter(declaredParamTypes, argTypes);

         if (
            firstRealParameter >= 0 &&
            (matchesParameterTypes(declaredParamTypes, argTypes, firstRealParameter) ||
             acceptsArgumentTypes(declaredParamTypes, argTypes, firstRealParameter)) &&
            (found == null || hasMoreSpecificTypes(declaredParamTypes, foundParameters))
         ) {
            //noinspection unchecked
            found = (Constructor) declaredConstructor;
            foundParameters = declaredParamTypes;
         }
      }

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

      Class declaringClass = theClass.getDeclaringClass();
      Class[] paramTypes = declaredConstructors[0].getParameterTypes();

      if (paramTypes[0] == declaringClass && paramTypes.length > argTypes.length) {
         throw new IllegalArgumentException("Invalid instantiation of inner class; use newInnerInstance instead");
      }

      String argTypesDesc = getParameterTypesDescription(argTypes);
      throw new IllegalArgumentException("No compatible constructor found: " + theClass.getSimpleName() + argTypesDesc);
   }

   public static  T newInstance(Class aClass, Object... nonNullArgs)
   {
      Class[] argTypes = getArgumentTypesFromArgumentValues(nonNullArgs);
      Constructor constructor = findCompatibleConstructor(aClass, argTypes);
      return invoke(constructor, nonNullArgs);
   }

   public static  T newInstance(Class aClass)
   {
      return newInstance(aClass, NO_PARAMETERS);
   }

   public static  T newInstanceUsingDefaultConstructor(Class aClass)
   {
      try {
         //noinspection ClassNewInstance
         return aClass.newInstance();
      }
      catch (InstantiationException ie) {
         throw new RuntimeException(ie);
      }
      catch (IllegalAccessException ignore) {
         return newInstance(aClass);
      }
   }

   public static  T newInnerInstance(Class innerClass, Object outerInstance, Object... nonNullArgs)
   {
      Object[] initArgs = argumentsWithExtraFirstValue(nonNullArgs, outerInstance);
      return newInstance(innerClass, initArgs);
   }

   public static  T newInnerInstance(String innerClassName, Object outerInstance, Object... nonNullArgs)
   {
      String className = outerInstance.getClass().getName() + '$' + innerClassName;
      Class innerClass = ClassLoad.loadClass(className);

      return newInnerInstance(innerClass, outerInstance, nonNullArgs);
   }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy