12637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin/*
22637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin * Copyright (c) 2007 Mockito contributors
32637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin * This program is made available under the terms of the MIT License.
42637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin */
52637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffinpackage org.mockito.internal.util.reflection;
62637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin
72637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffinimport org.mockito.exceptions.base.MockitoException;
82637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffinimport org.mockito.internal.util.MockUtil;
92637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin
102637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffinimport static java.lang.reflect.Modifier.isStatic;
112637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffinimport static org.mockito.internal.util.reflection.FieldSetter.setField;
122637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin
132637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffinimport java.lang.reflect.Constructor;
142637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffinimport java.lang.reflect.Field;
152637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffinimport java.lang.reflect.InvocationTargetException;
162637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffinimport java.lang.reflect.Modifier;
172637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffinimport java.util.Arrays;
182637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffinimport java.util.Collections;
192637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffinimport java.util.Comparator;
202637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffinimport java.util.List;
212637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin
222637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin/**
232637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin * Initialize a field with type instance if a default constructor can be found.
242637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin *
252637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin * <p>
262637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin * If the given field is already initialized, then <strong>the actual instance is returned</strong>.
272637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin * This initializer doesn't work with inner classes, local classes, interfaces or abstract types.
282637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin * </p>
292637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin *
302637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin */
312637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffinpublic class FieldInitializer {
322637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin
332637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin    private final Object fieldOwner;
342637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin    private final Field field;
352637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin    private final ConstructorInstantiator instantiator;
362637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin
372637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin
382637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin    /**
392637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin     * Prepare initializer with the given field on the given instance.
402637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin     *
412637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin     * <p>
422637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin     * This constructor fail fast if the field type cannot be handled.
432637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin     * </p>
442637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin     *
452637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin     * @param fieldOwner Instance of the test.
462637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin     * @param field Field to be initialize.
472637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin     */
482637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin    public FieldInitializer(Object fieldOwner, Field field) {
492637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin        this(fieldOwner, field, new NoArgConstructorInstantiator(fieldOwner, field));
502637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin    }
512637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin
522637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin    /**
532637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin     * Prepare initializer with the given field on the given instance.
542637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin     *
552637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin     * <p>
562637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin     * This constructor fail fast if the field type cannot be handled.
572637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin     * </p>
582637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin     *
592637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin     * @param fieldOwner Instance of the test.
602637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin     * @param field Field to be initialize.
612637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin     * @param argResolver Constructor parameters resolver
622637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin     */
632637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin    public FieldInitializer(Object fieldOwner, Field field, ConstructorArgumentResolver argResolver) {
642637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin        this(fieldOwner, field, new ParameterizedConstructorInstantiator(fieldOwner, field, argResolver));
652637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin    }
662637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin
672637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin    private FieldInitializer(Object fieldOwner, Field field, ConstructorInstantiator instantiator) {
682637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin        if(new FieldReader(fieldOwner, field).isNull()) {
692637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin            checkNotLocal(field);
702637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin            checkNotInner(field);
712637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin            checkNotInterface(field);
722637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin            checkNotEnum(field);
732637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin            checkNotAbstract(field);
742637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin
752637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin        }
762637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin        this.fieldOwner = fieldOwner;
772637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin        this.field = field;
782637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin        this.instantiator = instantiator;
792637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin    }
802637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin
812637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin    /**
822637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin     * Initialize field if not initialized and return the actual instance.
832637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin     *
842637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin     * @return Actual field instance.
852637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin     */
862637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin    public FieldInitializationReport initialize() {
872637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin        final AccessibilityChanger changer = new AccessibilityChanger();
882637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin        changer.enableAccess(field);
892637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin
902637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin        try {
912637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin            return acquireFieldInstance();
922637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin        } catch(IllegalAccessException e) {
932637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin            throw new MockitoException("Problems initializing field '" + field.getName() + "' of type '" + field.getType().getSimpleName() + "'", e);
942637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin        } finally {
952637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin            changer.safelyDisableAccess(field);
962637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin        }
972637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin    }
982637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin
992637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin    private void checkNotLocal(Field field) {
1002637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin        if(field.getType().isLocalClass()) {
1012637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin            throw new MockitoException("the type '" + field.getType().getSimpleName() + "' is a local class.");
1022637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin        }
1032637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin    }
1042637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin
1052637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin    private void checkNotInner(Field field) {
1062637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin        Class<?> type = field.getType();
1072637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin        if(type.isMemberClass() && !isStatic(type.getModifiers())) {
1082637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin            throw new MockitoException("the type '" + type.getSimpleName() + "' is an inner non static class.");
1092637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin        }
1102637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin    }
1112637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin
1122637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin    private void checkNotInterface(Field field) {
1132637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin        if(field.getType().isInterface()) {
1142637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin            throw new MockitoException("the type '" + field.getType().getSimpleName() + "' is an interface.");
1152637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin        }
1162637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin    }
1172637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin
1182637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin    private void checkNotAbstract(Field field) {
1192637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin        if(Modifier.isAbstract(field.getType().getModifiers())) {
1202637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin            throw new MockitoException("the type '" + field.getType().getSimpleName() + "' is an abstract class.");
1212637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin        }
1222637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin    }
1232637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin
1242637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin    private void checkNotEnum(Field field) {
1252637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin        if(field.getType().isEnum()) {
1262637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin            throw new MockitoException("the type '" + field.getType().getSimpleName() + "' is an enum.");
1272637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin        }
1282637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin    }
1292637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin
1302637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin
1312637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin    private FieldInitializationReport acquireFieldInstance() throws IllegalAccessException {
1322637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin        Object fieldInstance = field.get(fieldOwner);
1332637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin        if(fieldInstance != null) {
1342637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin            return new FieldInitializationReport(fieldInstance, false, false);
1352637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin        }
1362637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin
1372637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin        return instantiator.instantiate();
1382637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin    }
1392637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin
1402637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin    /**
1412637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin     * Represents the strategy used to resolve actual instances
1422637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin     * to be given to a constructor given the argument types.
1432637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin     */
1442637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin    public interface ConstructorArgumentResolver {
1452637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin
1462637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin        /**
1472637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin         * Try to resolve instances from types.
1482637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin         *
1492637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin         * <p>
1502637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin         * Checks on the real argument type or on the correct argument number
1512637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin         * will happen during the field initialization {@link FieldInitializer#initialize()}.
1522637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin         * I.e the only responsibility of this method, is to provide instances <strong>if possible</strong>.
1532637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin         * </p>
1542637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin         *
1552637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin         * @param argTypes Constructor argument types, should not be null.
1562637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin         * @return The argument instances to be given to the constructor, should not be null.
1572637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin         */
1582637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin        Object[] resolveTypeInstances(Class<?>... argTypes);
1592637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin    }
1602637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin
1612637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin    private interface ConstructorInstantiator {
1622637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin        FieldInitializationReport instantiate();
1632637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin    }
1642637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin
1652637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin    /**
1662637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin     * Constructor instantiating strategy for no-arg constructor.
1672637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin     *
1682637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin     * <p>
1692637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin     * If a no-arg constructor can be found then the instance is created using
1702637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin     * this constructor.
1712637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin     * Otherwise a technical MockitoException is thrown.
1722637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin     * </p>
1732637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin     */
1742637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin    static class NoArgConstructorInstantiator implements ConstructorInstantiator {
1752637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin        private final Object testClass;
1762637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin        private final Field field;
1772637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin
1782637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin        /**
1792637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin         * Internal, checks are done by FieldInitializer.
1802637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin         * Fields are assumed to be accessible.
1812637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin         */
1822637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin        NoArgConstructorInstantiator(Object testClass, Field field) {
1832637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin            this.testClass = testClass;
1842637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin            this.field = field;
1852637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin        }
1862637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin
1872637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin        public FieldInitializationReport instantiate() {
1882637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin            final AccessibilityChanger changer = new AccessibilityChanger();
1892637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin            Constructor<?> constructor = null;
1902637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin            try {
1912637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin                constructor = field.getType().getDeclaredConstructor();
1922637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin                changer.enableAccess(constructor);
1932637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin
1942637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin                final Object[] noArg = new Object[0];
1952637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin                Object newFieldInstance = constructor.newInstance(noArg);
1962637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin                setField(testClass, field,newFieldInstance);
1972637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin
1982637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin                return new FieldInitializationReport(field.get(testClass), true, false);
1992637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin            } catch (NoSuchMethodException e) {
2002637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin                throw new MockitoException("the type '" + field.getType().getSimpleName() + "' has no default constructor", e);
2012637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin            } catch (InvocationTargetException e) {
2022637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin                throw new MockitoException("the default constructor of type '" + field.getType().getSimpleName() + "' has raised an exception (see the stack trace for cause): " + e.getTargetException().toString(), e);
2032637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin            } catch (InstantiationException e) {
2042637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin                throw new MockitoException("InstantiationException (see the stack trace for cause): " + e.toString(), e);
2052637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin            } catch (IllegalAccessException e) {
2062637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin                throw new MockitoException("IllegalAccessException (see the stack trace for cause): " + e.toString(), e);
2072637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin            } finally {
2082637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin                if(constructor != null) {
2092637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin                    changer.safelyDisableAccess(constructor);
2102637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin                }
2112637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin            }
2122637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin        }
2132637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin    }
2142637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin
2152637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin    /**
2162637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin     * Constructor instantiating strategy for parameterized constructors.
2172637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin     *
2182637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin     * <p>
2192637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin     * Choose the constructor with the highest number of parameters, then
2202637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin     * call the ConstructorArgResolver to get actual argument instances.
2212637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin     * If the argResolver fail, then a technical MockitoException is thrown is thrown.
2222637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin     * Otherwise the instance is created with the resolved arguments.
2232637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin     * </p>
2242637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin     */
2252637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin    static class ParameterizedConstructorInstantiator implements ConstructorInstantiator {
2262637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin        private final Object testClass;
2272637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin        private final Field field;
2282637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin        private final ConstructorArgumentResolver argResolver;
2292637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin        private final Comparator<Constructor<?>> byParameterNumber = new Comparator<Constructor<?>>() {
2302637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin            public int compare(Constructor<?> constructorA, Constructor<?> constructorB) {
2312637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin                int argLengths = constructorB.getParameterTypes().length - constructorA.getParameterTypes().length;
2322637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin                if (argLengths == 0) {
2332637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin                    int constructorAMockableParamsSize = countMockableParams(constructorA);
2342637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin                    int constructorBMockableParamsSize = countMockableParams(constructorB);
2352637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin                    return constructorBMockableParamsSize - constructorAMockableParamsSize;
2362637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin                }
2372637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin                return argLengths;
2382637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin            }
2392637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin
2402637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin            private int countMockableParams(Constructor<?> constructor) {
2412637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin                int constructorMockableParamsSize = 0;
2422637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin                for (Class<?> aClass : constructor.getParameterTypes()) {
2432637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin                    if(MockUtil.typeMockabilityOf(aClass).mockable()){
2442637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin                        constructorMockableParamsSize++;
2452637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin                    }
2462637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin                }
2472637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin                return constructorMockableParamsSize;
2482637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin            }
2492637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin        };
2502637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin
2512637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin        /**
2522637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin         * Internal, checks are done by FieldInitializer.
2532637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin         * Fields are assumed to be accessible.
2542637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin         */
2552637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin        ParameterizedConstructorInstantiator(Object testClass, Field field, ConstructorArgumentResolver argumentResolver) {
2562637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin            this.testClass = testClass;
2572637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin            this.field = field;
2582637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin            this.argResolver = argumentResolver;
2592637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin        }
2602637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin
2612637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin        public FieldInitializationReport instantiate() {
2622637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin            final AccessibilityChanger changer = new AccessibilityChanger();
2632637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin            Constructor<?> constructor = null;
2642637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin            try {
2652637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin                constructor = biggestConstructor(field.getType());
2662637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin                changer.enableAccess(constructor);
2672637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin
2682637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin                final Object[] args = argResolver.resolveTypeInstances(constructor.getParameterTypes());
2692637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin                Object newFieldInstance = constructor.newInstance(args);
2702637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin                setField(testClass, field,newFieldInstance);
2712637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin
2722637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin                return new FieldInitializationReport(field.get(testClass), false, true);
2732637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin            } catch (IllegalArgumentException e) {
2742637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin                throw new MockitoException("internal error : argResolver provided incorrect types for constructor " + constructor + " of type " + field.getType().getSimpleName(), e);
2752637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin            } catch (InvocationTargetException e) {
2762637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin                throw new MockitoException("the constructor of type '" + field.getType().getSimpleName() + "' has raised an exception (see the stack trace for cause): " + e.getTargetException().toString(), e);
2772637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin            } catch (InstantiationException e) {
2782637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin                throw new MockitoException("InstantiationException (see the stack trace for cause): " + e.toString(), e);
2792637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin            } catch (IllegalAccessException e) {
2802637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin                throw new MockitoException("IllegalAccessException (see the stack trace for cause): " + e.toString(), e);
2812637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin            } finally {
2822637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin                if(constructor != null) {
2832637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin                    changer.safelyDisableAccess(constructor);
2842637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin                }
2852637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin            }
2862637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin        }
2872637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin
2882637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin        private void checkParameterized(Constructor<?> constructor, Field field) {
2892637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin            if(constructor.getParameterTypes().length == 0) {
2902637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin                throw new MockitoException("the field " + field.getName() + " of type " + field.getType() + " has no parameterized constructor");
2912637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin            }
2922637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin        }
2932637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin
2942637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin        private Constructor<?> biggestConstructor(Class<?> clazz) {
2952637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin            final List<? extends Constructor<?>> constructors = Arrays.asList(clazz.getDeclaredConstructors());
2962637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin            Collections.sort(constructors, byParameterNumber);
2972637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin
2982637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin            Constructor<?> constructor = constructors.get(0);
2992637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin            checkParameterized(constructor, field);
3002637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin            return constructor;
3012637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin        }
3022637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin    }
3032637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin}
304