Home | History | Annotate | Download | only in injection
      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