/* * 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> T newInstance(Class<T> aClass, Class<?>[] parameterTypes, Object... initArgs) { Constructor<T> constructor = findSpecifiedConstructor(aClass, parameterTypes); return invoke(constructor, initArgs); } private static <T> Constructor<T> 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<T>) declaredConstructor; } } String paramTypesDesc = getParameterTypesDescription(paramTypes); throw new IllegalArgumentException( "Specified constructor not found: " + theClass.getSimpleName() + paramTypesDesc); } public static <T> T invoke(Constructor<T> 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> T newInstance(String className, Class<?>[] parameterTypes, Object... initArgs) { Class<T> theClass = ClassLoad.loadClass(className); return newInstance(theClass, parameterTypes, initArgs); } public static <T> T newInstance(String className, Object... nonNullArgs) { Class<?>[] argTypes = getArgumentTypesFromArgumentValues(nonNullArgs); Class<T> theClass = ClassLoad.loadClass(className); Constructor<T> constructor = findCompatibleConstructor(theClass, argTypes); return invoke(constructor, nonNullArgs); } private static <T> Constructor<T> findCompatibleConstructor(Class<?> theClass, Class<?>[] argTypes) { Constructor<T> 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<T>) 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> T newInstance(Class<? extends T> aClass, Object... nonNullArgs) { Class<?>[] argTypes = getArgumentTypesFromArgumentValues(nonNullArgs); Constructor<T> constructor = findCompatibleConstructor(aClass, argTypes); return invoke(constructor, nonNullArgs); } public static <T> T newInstance(Class<T> aClass) { return newInstance(aClass, NO_PARAMETERS); } public static <T> T newInstanceUsingDefaultConstructor(Class<T> aClass) { try { //noinspection ClassNewInstance return aClass.newInstance(); } catch (InstantiationException ie) { throw new RuntimeException(ie); } catch (IllegalAccessException ignore) { return newInstance(aClass); } } public static <T> T newInnerInstance(Class<? extends T> innerClass, Object outerInstance, Object... nonNullArgs) { Object[] initArgs = argumentsWithExtraFirstValue(nonNullArgs, outerInstance); return newInstance(innerClass, initArgs); } public static <T> T newInnerInstance(String innerClassName, Object outerInstance, Object... nonNullArgs) { String className = outerInstance.getClass().getName() + '$' + innerClassName; Class<T> innerClass = ClassLoad.loadClass(className); return newInnerInstance(innerClass, outerInstance, nonNullArgs); } }