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