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