1 /* 2 * Copyright (c) 2007 Mockito contributors 3 * This program is made available under the terms of the MIT License. 4 */ 5 6 package org.mockito.internal.configuration.injection; 7 8 import org.mockito.exceptions.base.MockitoException; 9 import org.mockito.internal.util.reflection.FieldInitializationReport; 10 import org.mockito.internal.util.reflection.FieldInitializer; 11 import org.mockito.internal.util.reflection.FieldInitializer.ConstructorArgumentResolver; 12 13 import static org.mockito.internal.exceptions.Reporter.fieldInitialisationThrewException; 14 15 import java.lang.reflect.Field; 16 import java.lang.reflect.InvocationTargetException; 17 import java.util.ArrayList; 18 import java.util.List; 19 import java.util.Set; 20 21 /** 22 * Injection strategy based on constructor. 23 * 24 * <p> 25 * The strategy will search for the constructor with most parameters 26 * and try to resolve mocks by type. 27 * </p> 28 * 29 * <blockquote> 30 * TODO on missing mock type, shall it abandon or create "noname" mocks. 31 * TODO and what if the arg type is not mockable. 32 * </blockquote> 33 * 34 * <p> 35 * For now the algorithm tries to create anonymous mocks if an argument type is missing. 36 * If not possible the algorithm abandon resolution. 37 * </p> 38 */ 39 public class ConstructorInjection extends MockInjectionStrategy { 40 41 public ConstructorInjection() { } 42 43 public boolean processInjection(Field field, Object fieldOwner, Set<Object> mockCandidates) { 44 try { 45 SimpleArgumentResolver simpleArgumentResolver = new SimpleArgumentResolver(mockCandidates); 46 FieldInitializationReport report = new FieldInitializer(fieldOwner, field, simpleArgumentResolver).initialize(); 47 48 return report.fieldWasInitializedUsingContructorArgs(); 49 } catch (MockitoException e) { 50 if(e.getCause() instanceof InvocationTargetException) { 51 Throwable realCause = e.getCause().getCause(); 52 throw fieldInitialisationThrewException(field, realCause); 53 } 54 // other causes should be fine 55 return false; 56 } 57 58 } 59 60 /** 61 * Returns mocks that match the argument type, if not possible assigns null. 62 */ 63 static class SimpleArgumentResolver implements ConstructorArgumentResolver { 64 final Set<Object> objects; 65 66 public SimpleArgumentResolver(Set<Object> objects) { 67 this.objects = objects; 68 } 69 70 public Object[] resolveTypeInstances(Class<?>... argTypes) { 71 List<Object> argumentInstances = new ArrayList<Object>(argTypes.length); 72 for (Class<?> argType : argTypes) { 73 argumentInstances.add(objectThatIsAssignableFrom(argType)); 74 } 75 return argumentInstances.toArray(); 76 } 77 78 private Object objectThatIsAssignableFrom(Class<?> argType) { 79 for (Object object : objects) { 80 if(argType.isAssignableFrom(object.getClass())) return object; 81 } 82 return null; 83 } 84 } 85 86 } 87