imToken v2.14.1版本的 MD5 值为:83050b2c91219b46832c8336279e7878

以下内容为反编译后的 ConstructorInstantiator.java 源代码,内容仅作参考


package org.mockito.internal.creation.instance;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import org.mockito.creation.instance.InstantiationException;
import org.mockito.creation.instance.Instantiator;
import org.mockito.internal.configuration.plugins.Plugins;
import org.mockito.internal.util.Primitives;
import org.mockito.internal.util.StringUtil;
public class ConstructorInstantiator implements Instantiator {
    private final Object[] constructorArgs;
    private final boolean hasOuterClassInstance;

    public ConstructorInstantiator(boolean z2, Object... objArr) {
        this.hasOuterClassInstance = z2;
        this.constructorArgs = objArr;
    }

    @Override
    public <T> T newInstance(Class<T> cls) {
        return (T) withParams(cls, this.constructorArgs);
    }

    private <T> T withParams(Class<T> cls, Object... objArr) {
        Constructor<?>[] declaredConstructors;
        LinkedList linkedList = new LinkedList();
        try {
            for (Constructor<?> constructor : cls.getDeclaredConstructors()) {
                if (paramsMatch(constructor.getParameterTypes(), objArr)) {
                    evaluateConstructor(linkedList, constructor);
                }
            }
            if (linkedList.size() == 1) {
                return (T) invokeConstructor(linkedList.get(0), objArr);
            }
            if (linkedList.isEmpty()) {
                throw noMatchingConstructor(cls);
            }
            throw multipleMatchingConstructors(cls, linkedList);
        } catch (Exception e2) {
            throw paramsException(cls, e2);
        }
    }

    private static <T> T invokeConstructor(Constructor<?> constructor, Object... objArr) throws InstantiationException, IllegalAccessException, InvocationTargetException {
        return (T) Plugins.getMemberAccessor().newInstance(constructor, objArr);
    }

    private InstantiationException paramsException(Class<?> cls, Exception exc) {
        return new InstantiationException(StringUtil.join("Unable to create instance of '" + cls.getSimpleName() + "'.", "Please ensure the target class has " + constructorArgsString() + " and executes cleanly."), exc);
    }

    private String constructorArgTypes() {
        boolean z2 = this.hasOuterClassInstance;
        String[] strArr = new String[this.constructorArgs.length - (z2 ? 1 : 0)];
        int i2 = z2 ? 1 : 0;
        while (true) {
            Object[] objArr = this.constructorArgs;
            if (i2 < objArr.length) {
                strArr[i2 - (z2 ? 1 : 0)] = objArr[i2] == null ? null : objArr[i2].getClass().getName();
                i2++;
            } else {
                return Arrays.toString(strArr);
            }
        }
    }

    private InstantiationException noMatchingConstructor(Class<?> cls) {
        String constructorArgsString = constructorArgsString();
        String str = this.hasOuterClassInstance ? " and provided outer instance is correct" : "";
        return new InstantiationException(StringUtil.join("Unable to create instance of '" + cls.getSimpleName() + "'.", "Please ensure that the target class has " + constructorArgsString + str + "."), null);
    }

    private String constructorArgsString() {
        Object[] objArr = this.constructorArgs;
        if (objArr.length == 0 || (this.hasOuterClassInstance && objArr.length == 1)) {
            return "a 0-arg constructor";
        }
        return "a constructor that matches these argument types: " + constructorArgTypes();
    }

    private InstantiationException multipleMatchingConstructors(Class<?> cls, List<Constructor<?>> list) {
        return new InstantiationException(StringUtil.join("Unable to create instance of '" + cls.getSimpleName() + "'.", "Multiple constructors could be matched to arguments of types " + constructorArgTypes() + ":", StringUtil.join("", " - ", list), "If you believe that Mockito could do a better job deciding on which constructor to use, please let us know.", "Ticket 685 contains the discussion and a workaround for ambiguous constructors using inner class.", "See https://github.com/mockito/mockito/issues/685"), null);
    }

    private static boolean paramsMatch(Class<?>[] clsArr, Object[] objArr) {
        if (objArr.length != clsArr.length) {
            return false;
        }
        for (int i2 = 0; i2 < objArr.length; i2++) {
            if (objArr[i2] == null) {
                if (clsArr[i2].isPrimitive()) {
                    return false;
                }
            } else if ((!clsArr[i2].isPrimitive() && !clsArr[i2].isInstance(objArr[i2])) || (clsArr[i2].isPrimitive() && !clsArr[i2].equals(Primitives.primitiveTypeOf(objArr[i2].getClass())))) {
                return false;
            }
        }
        return true;
    }

    private void evaluateConstructor(List<Constructor<?>> list, Constructor<?> constructor) {
        Class<?>[] parameterTypes = constructor.getParameterTypes();
        boolean z2 = false;
        boolean z3 = false;
        for (int i2 = 0; i2 < parameterTypes.length; i2++) {
            Class<?> cls = parameterTypes[i2];
            if (!cls.isPrimitive()) {
                for (Constructor<?> constructor2 : list) {
                    Class<?> cls2 = constructor2.getParameterTypes()[i2];
                    if (cls != cls2) {
                        if (cls.isAssignableFrom(cls2)) {
                            z2 = true;
                        } else {
                            z3 = true;
                        }
                    }
                }
            }
        }
        if (!z2) {
            list.clear();
        }
        if (z3 || !z2) {
            list.add(constructor);
        }
    }
}