/* * Copyright (c) 2007 Mockito contributors * This program is made available under the terms of the MIT License. */ package org.mockito.internal.configuration.injection; import org.mockito.exceptions.base.MockitoException; import org.mockito.internal.util.reflection.FieldInitializationReport; import org.mockito.internal.util.reflection.FieldInitializer; import org.mockito.internal.util.reflection.FieldInitializer.ConstructorArgumentResolver; import static org.mockito.internal.exceptions.Reporter.fieldInitialisationThrewException; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.List; import java.util.Set; /** * Injection strategy based on constructor. * * <p> * The strategy will search for the constructor with most parameters * and try to resolve mocks by type. * </p> * * <blockquote> * TODO on missing mock type, shall it abandon or create "noname" mocks. * TODO and what if the arg type is not mockable. * </blockquote> * * <p> * For now the algorithm tries to create anonymous mocks if an argument type is missing. * If not possible the algorithm abandon resolution. * </p> */ public class ConstructorInjection extends MockInjectionStrategy { public ConstructorInjection() { } public boolean processInjection(Field field, Object fieldOwner, Set<Object> mockCandidates) { try { SimpleArgumentResolver simpleArgumentResolver = new SimpleArgumentResolver(mockCandidates); FieldInitializationReport report = new FieldInitializer(fieldOwner, field, simpleArgumentResolver).initialize(); return report.fieldWasInitializedUsingContructorArgs(); } catch (MockitoException e) { if(e.getCause() instanceof InvocationTargetException) { Throwable realCause = e.getCause().getCause(); throw fieldInitialisationThrewException(field, realCause); } // other causes should be fine return false; } } /** * Returns mocks that match the argument type, if not possible assigns null. */ static class SimpleArgumentResolver implements ConstructorArgumentResolver { final Set<Object> objects; public SimpleArgumentResolver(Set<Object> objects) { this.objects = objects; } public Object[] resolveTypeInstances(Class<?>... argTypes) { List<Object> argumentInstances = new ArrayList<Object>(argTypes.length); for (Class<?> argType : argTypes) { argumentInstances.add(objectThatIsAssignableFrom(argType)); } return argumentInstances.toArray(); } private Object objectThatIsAssignableFrom(Class<?> argType) { for (Object object : objects) { if(argType.isAssignableFrom(object.getClass())) return object; } return null; } } }