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

org.powermock.reflect.internal.ConstructorFinder Maven / Gradle / Ivy

There is a newer version: 2.0.9
Show newest version
package org.powermock.reflect.internal;

import org.powermock.reflect.exceptions.ConstructorNotFoundException;
import org.powermock.reflect.exceptions.TooManyConstructorsFoundException;

import java.lang.reflect.Modifier;
import java.util.HashSet;
import java.util.Set;

class ConstructorFinder {
    private Class type;
    private Object[] arguments;
    private Class unmockedType;
    private Constructor potentialConstructor;

    ConstructorFinder(Class type, Object... arguments) {
        if (type == null) {
            throw new IllegalArgumentException("Class type cannot be null.");
        }

        this.type = type;
        this.arguments = arguments;
        this.unmockedType = WhiteboxImpl.getOriginalUnmockedType(type);

        if (isNestedClass() && arguments != null) {
            addArgumentForNestedClass();
        }
    }

    public java.lang.reflect.Constructor findConstructor() {
        lookupPotentialConstructor();
        throwExceptionIfConstructorWasNotFound();
        return potentialConstructor.getJavaConstructor();
    }

    private void lookupPotentialConstructor() {Set constructors = getDeclaredConstructorsWithoutPowerMockConstructor();

        for (Constructor constructor : constructors) {
            if (constructor.canBeInvokeWith(arguments)) {
                setPotentialConstructor(constructor);
            }

            // if a constructor is found and it has varargs parameters then the constructor will be used even if
            // other constructor is matcher the given arguments. It is done, because when Argument Matchers are used
            // arguments passed to the method are null value and it's imposable to determinate whether parameters
            // match to arguments or not.

            if (isVarArgConstructorFound()){
                return;
            }
        }
    }

    private boolean isVarArgConstructorFound() {return potentialConstructor!=null && potentialConstructor.isVarArg();}

    private void setPotentialConstructor(Constructor constructor) {
        if (potentialConstructor == null) {
            potentialConstructor = constructor;
        }else{
                /*
                       * We've already found a constructor match before, this
                       * means that PowerMock cannot determine which method to
                       * expect since there are two methods with the same name
                       * and the same number of arguments but one is using
                       * wrapper types.
                       */
            throwExceptionWhenMultipleConstructorMatchesFound(new java.lang.reflect.Constructor[]{potentialConstructor.getJavaConstructor(),
                    constructor.getJavaConstructor()});
        }
    }

    public void throwExceptionWhenMultipleConstructorMatchesFound(java.lang.reflect.Constructor[] constructors) {
        if (constructors == null || constructors.length < 2) {
            throw new IllegalArgumentException("Internal error: throwExceptionWhenMultipleConstructorMatchesFound needs at least two constructors.");
        }
        StringBuilder sb = new StringBuilder();
        sb.append("Several matching constructors found, please specify the argument parameter types so that PowerMock can determine which method you're referring to.\n");
        sb.append("Matching constructors in class ").append(constructors[0].getDeclaringClass().getName())
          .append(" were:\n");

        for (java.lang.reflect.Constructor constructor : constructors) {
            sb.append(constructor.getName()).append("( ");
            final Class[] parameterTypes = constructor.getParameterTypes();
            for (Class paramType : parameterTypes) {
                sb.append(paramType.getName()).append(".class ");
            }
            sb.append(")\n");
        }
        throw new TooManyConstructorsFoundException(sb.toString());
    }

    private void addArgumentForNestedClass() {
        Object[] argumentsForLocalClass = new Object[arguments.length + 1];
        argumentsForLocalClass[0] = unmockedType.getEnclosingClass();
        System.arraycopy(arguments, 0, argumentsForLocalClass, 1, arguments.length);
        arguments = argumentsForLocalClass;
    }

    private boolean isNestedClass() {
        return (unmockedType.isLocalClass() || unmockedType.isAnonymousClass() || unmockedType.isMemberClass())
                       && !Modifier.isStatic(unmockedType.getModifiers());
    }

    private Set getDeclaredConstructorsWithoutPowerMockConstructor() {
        Set constructors = new HashSet();
        for (java.lang.reflect.Constructor constructor : unmockedType.getDeclaredConstructors()) {
            if (!isPowerMockConstructor(constructor.getParameterTypes())) {
                constructors.add(new Constructor(constructor));
            }
        }
        return constructors;
    }

    private boolean isPowerMockConstructor(Class[] parameterTypes) {
        return parameterTypes.length >= 1
                    && parameterTypes[parameterTypes.length - 1].getName().equals(
                "org.powermock.core.IndicateReloadClass");
    }

    private void throwExceptionIfConstructorWasNotFound() {
        if (potentialConstructor == null) {
            String message = "No constructor found in class '" + WhiteboxImpl.getOriginalUnmockedType(type).getName() + "' " +
                                     "with "
                                     + "parameter types: [ " + WhiteboxImpl.getArgumentTypesAsString(arguments) + " ].";
            throw new ConstructorNotFoundException(message);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy