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