View Javadoc
1   /*
2    * MIT License
3    * Copyright (c) 2006-2025 JMockit developers
4    * See LICENSE file for full license text.
5    */
6   package mockit.internal.expectations.mocking;
7   
8   import edu.umd.cs.findbugs.annotations.NonNull;
9   import edu.umd.cs.findbugs.annotations.Nullable;
10  
11  import java.lang.annotation.Annotation;
12  import java.lang.reflect.Type;
13  import java.util.ArrayList;
14  import java.util.List;
15  
16  import mockit.internal.util.TestMethod;
17  
18  import org.checkerframework.checker.index.qual.NonNegative;
19  
20  public final class ParameterTypeRedefinitions extends TypeRedefinitions {
21      @NonNull
22      private final TestMethod testMethod;
23      @NonNull
24      private final MockedType[] mockParameters;
25      @NonNull
26      private final List<MockedType> injectableParameters;
27  
28      public ParameterTypeRedefinitions(@NonNull TestMethod testMethod, @NonNull Object[] parameterValues) {
29          this.testMethod = testMethod;
30          int n = testMethod.getParameterCount();
31          mockParameters = new MockedType[n];
32          injectableParameters = new ArrayList<>(n);
33  
34          for (int i = 0; i < n; i++) {
35              Object mock = parameterValues[i];
36              createMockedTypeFromMockParameterDeclaration(i, mock);
37          }
38  
39          InstanceFactory[] instanceFactories = redefineMockedTypes();
40          instantiateMockedTypes(instanceFactories);
41      }
42  
43      private void createMockedTypeFromMockParameterDeclaration(@NonNegative int parameterIndex, @Nullable Object mock) {
44          Type parameterType = testMethod.getParameterType(parameterIndex);
45          Annotation[] annotationsOnParameter = testMethod.getParameterAnnotations(parameterIndex);
46          Class<?> parameterImplementationClass = mock == null ? null : mock.getClass();
47          MockedType mockedType = new MockedType(testMethod, parameterIndex, parameterType, annotationsOnParameter,
48                  parameterImplementationClass);
49  
50          if (mockedType.isMockableType()) {
51              mockParameters[parameterIndex] = mockedType;
52          }
53  
54          if (mockedType.injectable) {
55              injectableParameters.add(mockedType);
56              testMethod.setParameterValue(parameterIndex, mockedType.providedValue);
57          }
58      }
59  
60      @NonNull
61      private InstanceFactory[] redefineMockedTypes() {
62          int n = mockParameters.length;
63          InstanceFactory[] instanceFactories = new InstanceFactory[n];
64  
65          for (int i = 0; i < n; i++) {
66              MockedType mockedType = mockParameters[i];
67  
68              if (mockedType != null) {
69                  instanceFactories[i] = redefineMockedType(mockedType);
70              }
71          }
72  
73          return instanceFactories;
74      }
75  
76      @Nullable
77      private InstanceFactory redefineMockedType(@NonNull MockedType mockedType) {
78          TypeRedefinition typeRedefinition = new TypeRedefinition(mockedType);
79          InstanceFactory instanceFactory = typeRedefinition.redefineType();
80  
81          if (instanceFactory != null) {
82              addTargetClass(mockedType);
83          }
84  
85          return instanceFactory;
86      }
87  
88      private void registerCaptureOfNewInstances(@NonNull MockedType mockedType, @NonNull Object originalInstance) {
89          if (captureOfNewInstances == null) {
90              captureOfNewInstances = new CaptureOfNewInstances();
91          }
92  
93          captureOfNewInstances.registerCaptureOfNewInstances(mockedType, originalInstance);
94          captureOfNewInstances.makeSureAllSubtypesAreModified(mockedType);
95      }
96  
97      private void instantiateMockedTypes(@NonNull InstanceFactory[] instanceFactories) {
98          for (int paramIndex = 0; paramIndex < instanceFactories.length; paramIndex++) {
99              InstanceFactory instanceFactory = instanceFactories[paramIndex];
100 
101             if (instanceFactory != null) {
102                 MockedType mockedType = mockParameters[paramIndex];
103                 @NonNull
104                 Object mockedInstance = instantiateMockedType(mockedType, instanceFactory, paramIndex);
105                 testMethod.setParameterValue(paramIndex, mockedInstance);
106                 mockedType.providedValue = mockedInstance;
107             }
108         }
109     }
110 
111     @NonNull
112     private Object instantiateMockedType(@NonNull MockedType mockedType, @NonNull InstanceFactory instanceFactory,
113             @NonNegative int paramIndex) {
114         Object mock = testMethod.getParameterValue(paramIndex);
115 
116         if (mock == null) {
117             mock = instanceFactory.create();
118         }
119 
120         registerMock(mockedType, mock);
121 
122         if (mockedType.withInstancesToCapture()) {
123             registerCaptureOfNewInstances(mockedType, mock);
124         }
125 
126         return mock;
127     }
128 
129     @NonNull
130     public List<MockedType> getInjectableParameters() {
131         return injectableParameters;
132     }
133 }