• 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

94.39
/main/src/main/java/mockit/internal/faking/FakeMethods.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.faking;
7

8
import static java.lang.reflect.Modifier.isNative;
9

10
import static mockit.internal.util.ObjectMethods.isMethodFromObject;
11

12
import edu.umd.cs.findbugs.annotations.NonNull;
13
import edu.umd.cs.findbugs.annotations.Nullable;
14

15
import java.lang.annotation.Annotation;
16
import java.lang.reflect.Method;
17
import java.lang.reflect.Modifier;
18
import java.lang.reflect.Type;
19
import java.util.ArrayList;
20
import java.util.List;
21

22
import mockit.internal.ClassLoadingBridge;
23
import mockit.internal.reflection.GenericTypeReflection;
24
import mockit.internal.reflection.GenericTypeReflection.GenericSignature;
25
import mockit.internal.state.TestRun;
26
import mockit.internal.util.TypeDescriptor;
27
import mockit.internal.util.Utilities;
28

29
/**
30
 * A container for the fake methods "collected" from a fake class.
31
 */
32
final class FakeMethods {
33
    @NonNull
34
    private final Class<?> realClass;
35
    private final boolean targetTypeIsAClass;
36
    private final boolean reentrantRealClass;
37
    @NonNull
38
    private final List<FakeMethod> methods;
39
    @Nullable
40
    private FakeMethod adviceMethod;
41
    @NonNull
42
    private final GenericTypeReflection typeParametersToTypeArguments;
43
    @NonNull
44
    private String fakeClassInternalName;
45
    @Nullable
46
    private List<FakeState> fakeStates;
47

48
    final class FakeMethod {
49
        private final int access;
50
        @NonNull
51
        final String name;
52
        @NonNull
53
        final String desc;
54
        private final boolean isByNameOnly;
55
        final boolean isAdvice;
56
        @NonNull
57
        final String fakeDescWithoutInvocationParameter;
58
        private boolean hasMatchingRealMethod;
59
        @Nullable
60
        private GenericSignature fakeSignature;
61
        private int indexForFakeState;
62
        private boolean nativeRealMethod;
63

64
        private FakeMethod(int access, @NonNull String name, @NonNull String desc) {
1✔
65
            this.access = access;
1✔
66
            this.name = name;
1✔
67
            this.desc = desc;
1✔
68

69
            if (desc.contains("Lmockit/Invocation;")) {
1✔
70
                fakeDescWithoutInvocationParameter = '(' + desc.substring(20);
1✔
71
                isByNameOnly = name.charAt(0) != '$' && fakeDescWithoutInvocationParameter.startsWith("()");
1✔
72
                isAdvice = "$advice".equals(name) && "()Ljava/lang/Object;".equals(fakeDescWithoutInvocationParameter);
1!
73
            } else {
74
                fakeDescWithoutInvocationParameter = desc;
1✔
75
                isByNameOnly = false;
1✔
76
                isAdvice = false;
1✔
77
            }
78

79
            hasMatchingRealMethod = false;
1✔
80
            indexForFakeState = -1;
1✔
81
        }
1✔
82

83
        @SuppressWarnings("StringEquality")
84
        boolean hasInvocationParameter() {
85
            return desc != fakeDescWithoutInvocationParameter;
1✔
86
        }
87

88
        boolean hasInvocationParameterOnly() {
89
            return isByNameOnly || isAdvice;
1✔
90
        }
91

92
        boolean isMatch(int realAccess, @NonNull String realName, @NonNull String realDesc,
93
                @Nullable String signature) {
94
            if (name.equals(realName) && hasMatchingParameters(realDesc, signature)) {
1✔
95
                hasMatchingRealMethod = true;
1✔
96
                nativeRealMethod = isNative(realAccess);
1✔
97
                return true;
1✔
98
            }
99

100
            return false;
1✔
101
        }
102

103
        private boolean hasMatchingParameters(@NonNull String methodDesc, @Nullable String signature) {
104
            boolean sameParametersIgnoringGenerics = fakeDescWithoutInvocationParameter.equals(methodDesc);
1✔
105

106
            if (sameParametersIgnoringGenerics || signature == null) {
1✔
107
                return sameParametersIgnoringGenerics;
1✔
108
            }
109

110
            if (fakeSignature == null) {
1✔
111
                fakeSignature = typeParametersToTypeArguments.parseSignature(fakeDescWithoutInvocationParameter);
1✔
112
            }
113

114
            return fakeSignature.satisfiesGenericSignature(signature);
1✔
115
        }
116

117
        boolean isMatchByName(@NonNull String realName) {
118
            return isByNameOnly && name.equals(realName);
1✔
119
        }
120

121
        @NonNull
122
        Class<?> getRealClass() {
123
            return realClass;
1✔
124
        }
125

126
        int getIndexForFakeState() {
127
            return indexForFakeState;
1✔
128
        }
129

130
        boolean isStatic() {
131
            return Modifier.isStatic(access);
1✔
132
        }
133

134
        boolean isPublic() {
135
            return Modifier.isPublic(access);
1✔
136
        }
137

138
        boolean isForGenericMethod() {
139
            return fakeSignature != null;
1✔
140
        }
141

142
        boolean isForNativeMethod() {
143
            return nativeRealMethod;
1✔
144
        }
145

146
        boolean requiresFakeState() {
147
            return hasInvocationParameter() || reentrantRealClass;
1✔
148
        }
149

150
        boolean canBeReentered() {
151
            return targetTypeIsAClass && !nativeRealMethod;
1!
152
        }
153
    }
154

155
    FakeMethods(@NonNull Class<?> realClass, @Nullable Type targetType) {
1✔
156
        this.realClass = realClass;
1✔
157

158
        if (targetType == null || realClass == targetType) {
1✔
159
            targetTypeIsAClass = true;
1✔
160
        } else {
161
            Class<?> targetClass = Utilities.getClassType(targetType);
1✔
162
            targetTypeIsAClass = !targetClass.isInterface();
1✔
163
        }
164

165
        reentrantRealClass = targetTypeIsAClass
1✔
166
                && ClassLoadingBridge.instanceOfClassThatParticipatesInClassLoading(realClass);
1✔
167
        methods = new ArrayList<>();
1✔
168
        typeParametersToTypeArguments = new GenericTypeReflection(realClass, targetType);
1✔
169
        fakeClassInternalName = "";
1✔
170
    }
1✔
171

172
    @NonNull
173
    Class<?> getRealClass() {
174
        return realClass;
1✔
175
    }
176

177
    @Nullable
178
    FakeMethod addMethod(boolean fromSuperClass, int access, @NonNull String name, @NonNull String desc) {
179
        if (fromSuperClass && isMethodAlreadyAdded(name, desc)) {
1!
180
            return null;
×
181
        }
182

183
        FakeMethod fakeMethod = new FakeMethod(access, name, desc);
1✔
184

185
        if (fakeMethod.isAdvice) {
1✔
186
            adviceMethod = fakeMethod;
1✔
187
        } else {
188
            methods.add(fakeMethod);
1✔
189
        }
190

191
        return fakeMethod;
1✔
192
    }
193

194
    private boolean isMethodAlreadyAdded(@NonNull String name, @NonNull String desc) {
195
        int p = desc.lastIndexOf(')');
1✔
196
        String params = desc.substring(0, p + 1);
1✔
197

198
        for (FakeMethod fakeMethod : methods) {
1✔
199
            if (fakeMethod.name.equals(name) && fakeMethod.desc.startsWith(params)) {
1!
200
                return true;
×
201
            }
202
        }
1✔
203

204
        return false;
1✔
205
    }
206

207
    void addFakeState(@NonNull FakeState fakeState) {
208
        if (fakeStates == null) {
1✔
209
            fakeStates = new ArrayList<>(4);
1✔
210
        }
211

212
        fakeState.fakeMethod.indexForFakeState = fakeStates.size();
1✔
213
        fakeStates.add(fakeState);
1✔
214
    }
1✔
215

216
    /**
217
     * Finds a fake method with the same signature of a given real method, if previously collected from the fake class.
218
     * Also handles "match-by-name-only" fake methods with only the <code>Invocation</code> parameter, and the
219
     * <code>$advice</code> fake method.
220
     * <p>
221
     * This operation can be performed only once for any given fake method in this container, so that after the last
222
     * real method is processed there should be no fake methods left unused in the container.
223
     */
224
    @Nullable
225
    FakeMethod findMethod(int access, @NonNull String name, @NonNull String desc, @Nullable String signature) {
226
        FakeMethod fakeMethodMatchingByNameOnly = null;
1✔
227

228
        for (FakeMethod fakeMethod : methods) {
1✔
229
            if (fakeMethod.isMatch(access, name, desc, signature)) {
1✔
230
                // Mocking native methods with IntrinsicCandidate annotations will cause the VM to terminate illegally.
231
                if (isNative(access) && hasIntrinsicCandidateAnnotation(getRealClass(), name, desc)) {
1✔
232
                    throw new UnsupportedOperationException(
1✔
233
                            "Native methods annotated with IntrinsicCandidate cannot be mocked: "
234
                                    + getRealClass().getSimpleName() + "#" + name);
1✔
235
                }
236
                return fakeMethod;
1✔
237
            }
238

239
            if (fakeMethod.isMatchByName(name)) {
1✔
240
                fakeMethodMatchingByNameOnly = fakeMethod;
1✔
241
            }
242
        }
1✔
243

244
        if (fakeMethodMatchingByNameOnly != null) {
1✔
245
            return fakeMethodMatchingByNameOnly;
1✔
246
        }
247

248
        if (adviceMethod != null && !isNative(access) && !isConstructorOrClassInitialization(name)
1!
249
                && !isMethodFromObject(name, desc)) {
1✔
250
            return adviceMethod;
1✔
251
        }
252

253
        return null;
1✔
254
    }
255

256
    private boolean hasIntrinsicCandidateAnnotation(Class<?> clazz, String methodName, String methodDescriptor) {
257
        Class<?>[] parameterTypes = TypeDescriptor.getParameterTypes(methodDescriptor);
1✔
258

259
        try {
260
            // All access modifiers
261
            Method method = clazz.getDeclaredMethod(methodName, parameterTypes);
1✔
262
            Annotation[] annotations = method.getAnnotations();
1✔
263

264
            for (Annotation annotation : annotations) {
1✔
265
                String annotationName = annotation.annotationType().getSimpleName();
1✔
266
                // JDK11: jdk.internal.HotSpotIntrinsicCandidate
267
                // JDK17, 21: jdk.internal.vm.annotation.IntrinsicCandidate
268
                if (annotationName.contains("IntrinsicCandidate")) {
1!
269
                    return true;
1✔
270
                }
271
            }
272
        } catch (NoSuchMethodException e) {
×
273
            return false;
×
274
        }
1✔
275
        return false;
1✔
276
    }
277

278
    private static boolean isConstructorOrClassInitialization(@NonNull String memberName) {
279
        return "$init".equals(memberName) || "$clinit".equals(memberName);
1!
280
    }
281

282
    @NonNull
283
    String getFakeClassInternalName() {
284
        return fakeClassInternalName;
1✔
285
    }
286

287
    void setFakeClassInternalName(@NonNull String fakeClassInternalName) {
288
        this.fakeClassInternalName = fakeClassInternalName.intern();
1✔
289
    }
1✔
290

291
    boolean hasUnusedFakes() {
292
        if (adviceMethod != null) {
1✔
293
            return true;
1✔
294
        }
295

296
        for (FakeMethod method : methods) {
1✔
297
            if (!method.hasMatchingRealMethod) {
1✔
298
                return true;
1✔
299
            }
300
        }
1✔
301

302
        return false;
1✔
303
    }
304

305
    void registerFakeStates(@NonNull Object fake, boolean forStartupFake) {
306
        if (fakeStates != null) {
1✔
307
            FakeStates allFakeStates = TestRun.getFakeStates();
1✔
308

309
            if (forStartupFake) {
1✔
310
                allFakeStates.addStartupFakeAndItsFakeStates(fake, fakeStates);
1✔
311
            } else {
312
                allFakeStates.addFakeAndItsFakeStates(fake, fakeStates);
1✔
313
            }
314
        }
315
    }
1✔
316
}
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