• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

hazendaz / jmockit1 / 496

15 Nov 2025 05:33PM UTC coverage: 72.192% (-0.008%) from 72.2%
496

push

github

web-flow
Merge pull request #412 from hazendaz/renovate/major-spring-core

Update spring core to v7 (major)

5677 of 8360 branches covered (67.91%)

Branch coverage included in aggregate %.

11922 of 16018 relevant lines covered (74.43%)

0.74 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.4
/main/src/main/java/mockit/internal/expectations/state/MockedTypeCascade.java
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.state;
7

8
import static java.lang.reflect.Modifier.INTERFACE;
9
import static java.lang.reflect.Modifier.PUBLIC;
10
import static java.lang.reflect.Modifier.isPublic;
11
import static java.util.Collections.synchronizedList;
12

13
import static mockit.asm.types.JavaType.getInternalName;
14
import static mockit.internal.util.Utilities.containsReference;
15
import static mockit.internal.util.Utilities.getClassType;
16

17
import edu.umd.cs.findbugs.annotations.NonNull;
18
import edu.umd.cs.findbugs.annotations.Nullable;
19

20
import java.lang.reflect.Method;
21
import java.lang.reflect.ParameterizedType;
22
import java.lang.reflect.Type;
23
import java.lang.reflect.TypeVariable;
24
import java.util.ArrayList;
25
import java.util.List;
26
import java.util.Map;
27
import java.util.concurrent.ConcurrentHashMap;
28

29
import mockit.internal.expectations.MockingFilters;
30
import mockit.internal.expectations.mocking.CascadingTypeRedefinition;
31
import mockit.internal.expectations.mocking.InstanceFactory;
32
import mockit.internal.reflection.GenericTypeReflection;
33
import mockit.internal.reflection.RealMethodOrConstructor;
34
import mockit.internal.state.TestRun;
35
import mockit.internal.util.DefaultValues;
36

37
public final class MockedTypeCascade {
38
    @NonNull
39
    private static final CascadingTypes CASCADING_TYPES = TestRun.getExecutingTest().getCascadingTypes();
1✔
40
    private static final int PUBLIC_INTERFACE = PUBLIC + INTERFACE;
41

42
    final boolean fromMockField;
43
    @NonNull
44
    private final Type mockedType;
45
    @NonNull
46
    final String mockedTypeDesc;
47
    @Nullable
48
    Class<?> mockedClass;
49
    @Nullable
50
    private GenericTypeReflection genericReflection;
51
    @NonNull
52
    private final Map<String, Type> cascadedTypesAndMocks;
53
    @NonNull
54
    private final List<Object> cascadingInstances;
55

56
    MockedTypeCascade(boolean fromMockField, @NonNull Type mockedType, @NonNull String mockedTypeDesc) {
1✔
57
        this.fromMockField = fromMockField;
1✔
58
        this.mockedType = mockedType;
1✔
59
        this.mockedTypeDesc = mockedTypeDesc;
1✔
60
        cascadedTypesAndMocks = new ConcurrentHashMap<>(4);
1✔
61
        cascadingInstances = synchronizedList(new ArrayList<>());
1✔
62
    }
1✔
63

64
    @Nullable
65
    public static Object getMock(@NonNull String mockedTypeDesc, @NonNull String mockedMethodNameAndDesc,
66
            @Nullable Object mockInstance, @NonNull String returnTypeDesc, @NonNull Class<?> returnType) {
67
        MockedTypeCascade cascade = CASCADING_TYPES.getCascade(mockedTypeDesc, mockInstance);
1✔
68

69
        if (cascade == null) {
1!
70
            return null;
×
71
        }
72

73
        String cascadedReturnTypeDesc = getReturnTypeIfCascadingSupportedForIt(returnTypeDesc);
1✔
74

75
        if (cascadedReturnTypeDesc == null) {
1!
76
            return null;
×
77
        }
78

79
        return cascade.getCascadedInstance(mockedMethodNameAndDesc, cascadedReturnTypeDesc, returnType);
1✔
80
    }
81

82
    @Nullable
83
    public static Object getMock(@NonNull String mockedTypeDesc, @NonNull String mockedMethodNameAndDesc,
84
            @Nullable Object mockInstance, @NonNull String returnTypeDesc, @Nullable String genericSignature) {
85
        char typeCode = returnTypeDesc.charAt(0);
1✔
86

87
        if (typeCode != 'L') {
1!
88
            return null;
×
89
        }
90

91
        MockedTypeCascade cascade = CASCADING_TYPES.getCascade(mockedTypeDesc, mockInstance);
1✔
92

93
        if (cascade == null) {
1✔
94
            return null;
1✔
95
        }
96

97
        String resolvedReturnTypeDesc = null;
1✔
98

99
        if (genericSignature != null) {
1✔
100
            resolvedReturnTypeDesc = cascade.getGenericReturnType(mockedTypeDesc, genericSignature);
1✔
101
        }
102

103
        if (resolvedReturnTypeDesc == null) {
1✔
104
            resolvedReturnTypeDesc = getReturnTypeIfCascadingSupportedForIt(returnTypeDesc);
1✔
105

106
            if (resolvedReturnTypeDesc == null) {
1✔
107
                return null;
1✔
108
            }
109
        } else if (resolvedReturnTypeDesc.charAt(0) == '[') {
1✔
110
            return DefaultValues.computeForArrayType(resolvedReturnTypeDesc);
1✔
111
        }
112

113
        return cascade.getCascadedInstance(mockedMethodNameAndDesc, resolvedReturnTypeDesc, mockInstance);
1✔
114
    }
115

116
    @Nullable
117
    private String getGenericReturnType(@NonNull String ownerTypeDesc, @NonNull String genericSignature) {
118
        String resolvedSignature = getGenericReflection().resolveSignature(ownerTypeDesc, genericSignature);
1✔
119
        String returnTypeDesc = resolvedSignature.substring(resolvedSignature.indexOf(')') + 1);
1✔
120

121
        if (returnTypeDesc.charAt(0) == '[') {
1✔
122
            return returnTypeDesc;
1✔
123
        }
124

125
        String returnTypeName = returnTypeDesc.substring(1, returnTypeDesc.length() - 1);
1✔
126
        return isTypeSupportedForCascading(returnTypeName) ? returnTypeName : null;
1✔
127
    }
128

129
    @NonNull
130
    private synchronized GenericTypeReflection getGenericReflection() {
131
        GenericTypeReflection reflection = genericReflection;
1✔
132

133
        if (reflection == null) {
1✔
134
            Class<?> ownerClass = getClassWithCalledMethod();
1✔
135
            reflection = new GenericTypeReflection(ownerClass, mockedType);
1✔
136
            genericReflection = reflection;
1✔
137
        }
138

139
        return reflection;
1✔
140
    }
141

142
    private static boolean isReturnTypeNotSupportedForCascading(@NonNull Class<?> returnType) {
143
        return MockingFilters.isSubclassOfUnmockable(returnType)
1✔
144
                || !isTypeSupportedForCascading(getInternalName(returnType));
1✔
145
    }
146

147
    @SuppressWarnings("OverlyComplexMethod")
148
    private static boolean isTypeSupportedForCascading(@NonNull String typeName) {
149
        // noinspection SimplifiableIfStatement
150
        if (typeName.contains("/Process") || typeName.endsWith("/Runnable")) {
1✔
151
            return true;
1✔
152
        }
153

154
        return (!typeName.startsWith("java/lang/") || typeName.contains("management"))
1✔
155
                && !typeName.startsWith("java/math/")
1✔
156
                && (!typeName.startsWith("java/util/") || typeName.endsWith("/Date") || typeName.endsWith("/Callable")
1✔
157
                        || typeName.endsWith("Future") || typeName.contains("logging"))
1✔
158
                && !"java/time/Duration".equals(typeName);
1✔
159
    }
160

161
    @Nullable
162
    private static String getReturnTypeIfCascadingSupportedForIt(@NonNull String typeDesc) {
163
        String typeName = typeDesc.substring(1, typeDesc.length() - 1);
1✔
164
        return isTypeSupportedForCascading(typeName) ? typeName : null;
1✔
165
    }
166

167
    @Nullable
168
    private Object getCascadedInstance(@NonNull String methodNameAndDesc, @NonNull String returnTypeInternalName,
169
            @NonNull Class<?> returnClass) {
170
        MockedTypeCascade nextLevel = this;
1✔
171

172
        if (!cascadedTypesAndMocks.containsKey(returnTypeInternalName)) {
1!
173
            cascadedTypesAndMocks.put(returnTypeInternalName, returnClass);
1✔
174
            nextLevel = CASCADING_TYPES.add(returnTypeInternalName, false, returnClass);
1✔
175
        }
176

177
        return nextLevel.createNewCascadedInstanceOrUseNonCascadedOneIfAvailable(methodNameAndDesc, returnClass);
1✔
178
    }
179

180
    @Nullable
181
    private Object getCascadedInstance(@NonNull String methodNameAndDesc, @NonNull String returnTypeInternalName,
182
            @Nullable Object mockInstance) {
183
        MockedTypeCascade nextLevel = this;
1✔
184
        Type returnType = cascadedTypesAndMocks.get(returnTypeInternalName);
1✔
185

186
        if (returnType == null) {
1✔
187
            Class<?> cascadingClass = getClassWithCalledMethod();
1✔
188
            Type genericReturnType = getGenericReturnType(cascadingClass, methodNameAndDesc);
1✔
189

190
            if (genericReturnType == null) {
1✔
191
                return null;
1✔
192
            }
193

194
            Class<?> resolvedReturnType = getClassType(genericReturnType);
1✔
195

196
            if (resolvedReturnType.isAssignableFrom(cascadingClass)) {
1✔
197
                if (mockInstance != null) {
1✔
198
                    return mockInstance;
1✔
199
                }
200

201
                returnType = mockedType;
1✔
202
            } else if (nonPublicTypeReturnedFromPublicInterface(cascadingClass, resolvedReturnType)
1✔
203
                    || isReturnTypeNotSupportedForCascading(resolvedReturnType)) {
1✔
204
                return null;
1✔
205
            } else {
206
                Object defaultReturnValue = DefaultValues.computeForType(resolvedReturnType);
1✔
207

208
                if (defaultReturnValue != null) {
1!
209
                    return defaultReturnValue;
×
210
                }
211

212
                cascadedTypesAndMocks.put(returnTypeInternalName, genericReturnType);
1✔
213
                nextLevel = CASCADING_TYPES.add(returnTypeInternalName, false, genericReturnType);
1✔
214
                returnType = genericReturnType;
1✔
215
            }
216
        } else {
1✔
217
            nextLevel = CASCADING_TYPES.getCascade(returnType);
1✔
218
        }
219

220
        return nextLevel.createNewCascadedInstanceOrUseNonCascadedOneIfAvailable(methodNameAndDesc, returnType);
1✔
221
    }
222

223
    private static boolean nonPublicTypeReturnedFromPublicInterface(@NonNull Class<?> cascadingClass,
224
            @NonNull Class<?> resolvedReturnType) {
225
        return cascadingClass.isInterface() && !isPublic(resolvedReturnType.getModifiers())
1✔
226
                && cascadingClass.getClassLoader() != null && (cascadingClass.getModifiers() & PUBLIC_INTERFACE) != 0
1!
227
                && !resolvedReturnType.isMemberClass();
1✔
228
    }
229

230
    @NonNull
231
    private Class<?> getClassWithCalledMethod() {
232
        if (mockedClass != null) {
1!
233
            return mockedClass;
×
234
        }
235

236
        if (mockedType instanceof Class<?>) {
1✔
237
            return (Class<?>) mockedType;
1✔
238
        }
239

240
        return (Class<?>) ((ParameterizedType) mockedType).getRawType();
1✔
241
    }
242

243
    @Nullable
244
    private Type getGenericReturnType(@NonNull Class<?> cascadingClass, @NonNull String methodNameAndDesc) {
245
        RealMethodOrConstructor realMethod;
246

247
        try {
248
            realMethod = new RealMethodOrConstructor(cascadingClass, methodNameAndDesc);
1✔
249
        } catch (NoSuchMethodException e) {
1✔
250
            return null;
1✔
251
        }
1✔
252

253
        Method cascadingMethod = realMethod.getMember();
1✔
254
        Type genericReturnType = cascadingMethod.getGenericReturnType();
1✔
255

256
        if (genericReturnType instanceof TypeVariable<?>) {
1✔
257
            genericReturnType = getGenericReflection().resolveTypeVariable((TypeVariable<?>) genericReturnType);
1✔
258
        }
259

260
        return genericReturnType == Object.class ? null : genericReturnType;
1✔
261
    }
262

263
    @Nullable
264
    private Object createNewCascadedInstanceOrUseNonCascadedOneIfAvailable(@NonNull String methodNameAndDesc,
265
            @NonNull Type mockedReturnType) {
266
        InstanceFactory instanceFactory = TestRun.mockFixture().findInstanceFactory(mockedReturnType);
1✔
267

268
        if (instanceFactory == null) {
1✔
269
            String methodName = methodNameAndDesc.substring(0, methodNameAndDesc.indexOf('('));
1✔
270
            CascadingTypeRedefinition typeRedefinition = new CascadingTypeRedefinition(methodName, mockedReturnType);
1✔
271
            instanceFactory = typeRedefinition.redefineType();
1✔
272

273
            if (instanceFactory == null) {
1!
274
                return null;
×
275
            }
276
        } else {
1✔
277
            Object lastInstance = instanceFactory.getLastInstance();
1✔
278

279
            if (lastInstance != null) {
1✔
280
                return lastInstance;
1✔
281
            }
282
        }
283

284
        Object cascadedInstance = instanceFactory.create();
1✔
285
        instanceFactory.clearLastInstance();
1✔
286
        addInstance(cascadedInstance);
1✔
287
        TestRun.getExecutingTest().addInjectableMock(cascadedInstance);
1✔
288
        return cascadedInstance;
1✔
289
    }
290

291
    void discardCascadedMocks() {
292
        cascadedTypesAndMocks.clear();
1✔
293
        cascadingInstances.clear();
1✔
294
    }
1✔
295

296
    void addInstance(@NonNull Object cascadingInstance) {
297
        cascadingInstances.add(cascadingInstance);
1✔
298
    }
1✔
299

300
    boolean hasInstance(@NonNull Object cascadingInstance) {
301
        return containsReference(cascadingInstances, cascadingInstance);
1✔
302
    }
303
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc