12637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin/* 22637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin * Copyright (c) 2016 Mockito contributors 32637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin * This program is made available under the terms of the MIT License. 42637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin */ 5e03a0f42b85425bffd40bcf790819671a7848c1aPaul Duffinpackage org.mockito.internal.creation.instance; 6e03a0f42b85425bffd40bcf790819671a7848c1aPaul Duffin 7e03a0f42b85425bffd40bcf790819671a7848c1aPaul Duffinimport java.lang.reflect.Constructor; 808bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmannimport java.lang.reflect.InvocationTargetException; 908bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmannimport java.util.Arrays; 1008bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmannimport java.util.LinkedList; 1108bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmannimport java.util.List; 1208bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann 13bf8c1ad2adfe37bae65749ebc46f76c72b475f32Philip P. Moltmannimport org.mockito.creation.instance.Instantiator; 14bf8c1ad2adfe37bae65749ebc46f76c72b475f32Philip P. Moltmannimport org.mockito.creation.instance.InstantiationException; 1508bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmannimport org.mockito.internal.util.Primitives; 162637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffinimport org.mockito.internal.util.reflection.AccessibilityChanger; 172637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin 182637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffinimport static org.mockito.internal.util.StringUtil.join; 19e03a0f42b85425bffd40bcf790819671a7848c1aPaul Duffin 20e03a0f42b85425bffd40bcf790819671a7848c1aPaul Duffinpublic class ConstructorInstantiator implements Instantiator { 21e03a0f42b85425bffd40bcf790819671a7848c1aPaul Duffin 2208bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann /** 2308bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann * Whether or not the constructors used for creating an object refer to an outer instance or not. 2408bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann * This member is only used to for constructing error messages. 2508bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann * If an outer inject exists, it would be the first ([0]) element of the {@link #constructorArgs} array. 2608bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann */ 2708bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann private final boolean hasOuterClassInstance; 2808bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann private final Object[] constructorArgs; 29e03a0f42b85425bffd40bcf790819671a7848c1aPaul Duffin 3008bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann public ConstructorInstantiator(boolean hasOuterClassInstance, Object... constructorArgs) { 3108bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann this.hasOuterClassInstance = hasOuterClassInstance; 3208bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann this.constructorArgs = constructorArgs; 33e03a0f42b85425bffd40bcf790819671a7848c1aPaul Duffin } 34e03a0f42b85425bffd40bcf790819671a7848c1aPaul Duffin 35e03a0f42b85425bffd40bcf790819671a7848c1aPaul Duffin public <T> T newInstance(Class<T> cls) { 3608bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann return withParams(cls, constructorArgs); 37e03a0f42b85425bffd40bcf790819671a7848c1aPaul Duffin } 38e03a0f42b85425bffd40bcf790819671a7848c1aPaul Duffin 3908bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann private <T> T withParams(Class<T> cls, Object... params) { 4008bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann List<Constructor<?>> matchingConstructors = new LinkedList<Constructor<?>>(); 41e03a0f42b85425bffd40bcf790819671a7848c1aPaul Duffin try { 42e03a0f42b85425bffd40bcf790819671a7848c1aPaul Duffin for (Constructor<?> constructor : cls.getDeclaredConstructors()) { 43e03a0f42b85425bffd40bcf790819671a7848c1aPaul Duffin Class<?>[] types = constructor.getParameterTypes(); 44e03a0f42b85425bffd40bcf790819671a7848c1aPaul Duffin if (paramsMatch(types, params)) { 4508bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann evaluateConstructor(matchingConstructors, constructor); 46e03a0f42b85425bffd40bcf790819671a7848c1aPaul Duffin } 47e03a0f42b85425bffd40bcf790819671a7848c1aPaul Duffin } 4808bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann 4908bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann if (matchingConstructors.size() == 1) { 5008bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann return invokeConstructor(matchingConstructors.get(0), params); 5108bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann } 52e03a0f42b85425bffd40bcf790819671a7848c1aPaul Duffin } catch (Exception e) { 53e03a0f42b85425bffd40bcf790819671a7848c1aPaul Duffin throw paramsException(cls, e); 54e03a0f42b85425bffd40bcf790819671a7848c1aPaul Duffin } 5508bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann if (matchingConstructors.size() == 0) { 5608bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann throw noMatchingConstructor(cls); 5708bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann } else { 5808bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann throw multipleMatchingConstructors(cls, matchingConstructors); 5908bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann } 602637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin } 612637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin 622637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin @SuppressWarnings("unchecked") 6308bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann private static <T> T invokeConstructor(Constructor<?> constructor, Object... params) throws java.lang.InstantiationException, IllegalAccessException, InvocationTargetException { 642637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin AccessibilityChanger accessibility = new AccessibilityChanger(); 652637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin accessibility.enableAccess(constructor); 662637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin return (T) constructor.newInstance(params); 672637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin } 682637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin 6908bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann private InstantiationException paramsException(Class<?> cls, Exception e) { 7008bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann return new InstantiationException(join( 7108bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann "Unable to create instance of '" + cls.getSimpleName() + "'.", 7208bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann "Please ensure the target class has " + constructorArgsString() + " and executes cleanly.") 7308bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann , e); 74e03a0f42b85425bffd40bcf790819671a7848c1aPaul Duffin } 75e03a0f42b85425bffd40bcf790819671a7848c1aPaul Duffin 7608bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann private String constructorArgTypes() { 7708bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann int argPos = 0; 7808bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann if (hasOuterClassInstance) { 7908bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann ++argPos; 8008bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann } 8108bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann String[] constructorArgTypes = new String[constructorArgs.length - argPos]; 8208bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann for (int i = argPos; i < constructorArgs.length; ++i) { 8308bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann constructorArgTypes[i - argPos] = constructorArgs[i] == null ? null : constructorArgs[i].getClass().getName(); 8408bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann } 8508bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann return Arrays.toString(constructorArgTypes); 8608bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann } 8708bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann 8808bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann private InstantiationException noMatchingConstructor(Class<?> cls) { 8908bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann String constructorString = constructorArgsString(); 9008bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann String outerInstanceHint = ""; 9108bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann if (hasOuterClassInstance) { 9208bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann outerInstanceHint = " and provided outer instance is correct"; 9308bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann } 9408bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann return new InstantiationException(join("Unable to create instance of '" + cls.getSimpleName() + "'.", 9508bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann "Please ensure that the target class has " + constructorString + outerInstanceHint + ".") 962637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin , null); 97e03a0f42b85425bffd40bcf790819671a7848c1aPaul Duffin } 98e03a0f42b85425bffd40bcf790819671a7848c1aPaul Duffin 9908bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann private String constructorArgsString() { 10008bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann String constructorString; 10108bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann if (constructorArgs.length == 0 || (hasOuterClassInstance && constructorArgs.length == 1)) { 10208bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann constructorString = "a 0-arg constructor"; 10308bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann } else { 10408bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann constructorString = "a constructor that matches these argument types: " + constructorArgTypes(); 10508bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann } 10608bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann return constructorString; 10708bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann } 10808bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann 10908bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann private InstantiationException multipleMatchingConstructors(Class<?> cls, List<Constructor<?>> constructors) { 11008bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann return new InstantiationException(join("Unable to create instance of '" + cls.getSimpleName() + "'.", 11108bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann "Multiple constructors could be matched to arguments of types " + constructorArgTypes() + ":", 11208bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann join("", " - ", constructors), 11308bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann "If you believe that Mockito could do a better job deciding on which constructor to use, please let us know.", 11408bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann "Ticket 685 contains the discussion and a workaround for ambiguous constructors using inner class.", 11508bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann "See https://github.com/mockito/mockito/issues/685" 11608bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann ), null); 11708bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann } 11808bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann 119e03a0f42b85425bffd40bcf790819671a7848c1aPaul Duffin private static boolean paramsMatch(Class<?>[] types, Object[] params) { 120e03a0f42b85425bffd40bcf790819671a7848c1aPaul Duffin if (params.length != types.length) { 121e03a0f42b85425bffd40bcf790819671a7848c1aPaul Duffin return false; 122e03a0f42b85425bffd40bcf790819671a7848c1aPaul Duffin } 123e03a0f42b85425bffd40bcf790819671a7848c1aPaul Duffin for (int i = 0; i < params.length; i++) { 12408bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann if (params[i] == null) { 12508bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann if (types[i].isPrimitive()) { 12608bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann return false; 12708bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann } 12808bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann } else if ((!types[i].isPrimitive() && !types[i].isInstance(params[i])) || 12908bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann (types[i].isPrimitive() && !types[i].equals(Primitives.primitiveTypeOf(params[i].getClass())))) { 130e03a0f42b85425bffd40bcf790819671a7848c1aPaul Duffin return false; 131e03a0f42b85425bffd40bcf790819671a7848c1aPaul Duffin } 132e03a0f42b85425bffd40bcf790819671a7848c1aPaul Duffin } 133e03a0f42b85425bffd40bcf790819671a7848c1aPaul Duffin return true; 134e03a0f42b85425bffd40bcf790819671a7848c1aPaul Duffin } 135e03a0f42b85425bffd40bcf790819671a7848c1aPaul Duffin 13608bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann /** 13708bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann * Evalutes {@code constructor} against the currently found {@code matchingConstructors} and determines if 13808bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann * it's a better match to the given arguments, a worse match, or an equivalently good match. 13908bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann * <p> 14008bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann * This method tries to emulate the behavior specified in 14108bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann * <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.12.2">JLS 15.12.2. Compile-Time 14208bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann * Step 2: Determine Method Signature</a>. A constructor X is deemed to be a better match than constructor Y to the 14308bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann * given argument list if they are both applicable, constructor X has at least one parameter than is more specific 14408bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann * than the corresponding parameter of constructor Y, and constructor Y has no parameter than is more specific than 14508bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann * the corresponding parameter in constructor X. 14608bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann * </p> 14708bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann * <p> 14808bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann * If {@code constructor} is a better match than the constructors in the {@code matchingConstructors} list, the list 14908bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann * is cleared, and it's added to the list as a singular best matching constructor (so far).<br/> 15008bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann * If {@code constructor} is an equivalently good of a match as the constructors in the {@code matchingConstructors} 15108bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann * list, it's added to the list.<br/> 15208bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann * If {@code constructor} is a worse match than the constructors in the {@code matchingConstructors} list, the list 15308bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann * will remain unchanged. 15408bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann * </p> 15508bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann * 15608bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann * @param matchingConstructors A list of equivalently best matching constructors found so far 15708bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann * @param constructor The constructor to be evaluated against this list 15808bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann */ 15908bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann private void evaluateConstructor(List<Constructor<?>> matchingConstructors, Constructor<?> constructor) { 16008bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann boolean newHasBetterParam = false; 16108bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann boolean existingHasBetterParam = false; 16208bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann 16308bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann Class<?>[] paramTypes = constructor.getParameterTypes(); 16408bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann for (int i = 0; i < paramTypes.length; ++i) { 16508bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann Class<?> paramType = paramTypes[i]; 16608bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann if (!paramType.isPrimitive()) { 16708bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann for (Constructor<?> existingCtor : matchingConstructors) { 16808bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann Class<?> existingParamType = existingCtor.getParameterTypes()[i]; 16908bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann if (paramType != existingParamType) { 17008bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann if (paramType.isAssignableFrom(existingParamType)) { 17108bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann existingHasBetterParam = true; 17208bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann } else { 17308bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann newHasBetterParam = true; 17408bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann } 17508bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann } 17608bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann } 17708bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann } 17808bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann } 17908bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann if (!existingHasBetterParam) { 18008bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann matchingConstructors.clear(); 18108bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann } 18208bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann if (newHasBetterParam || !existingHasBetterParam) { 18308bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann matchingConstructors.add(constructor); 184e03a0f42b85425bffd40bcf790819671a7848c1aPaul Duffin } 185e03a0f42b85425bffd40bcf790819671a7848c1aPaul Duffin } 186e03a0f42b85425bffd40bcf790819671a7848c1aPaul Duffin} 187