• 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.4
/main/src/main/java/mockit/internal/classGeneration/BaseSubclassGenerator.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.classGeneration;
7

8
import static java.util.Arrays.asList;
9

10
import static mockit.asm.jvmConstants.Opcodes.ALOAD;
11
import static mockit.asm.jvmConstants.Opcodes.INVOKESPECIAL;
12

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

16
import java.lang.reflect.Method;
17
import java.lang.reflect.Type;
18
import java.util.ArrayList;
19
import java.util.HashSet;
20
import java.util.List;
21
import java.util.Set;
22

23
import mockit.asm.classes.ClassInfo;
24
import mockit.asm.classes.ClassReader;
25
import mockit.asm.fields.FieldVisitor;
26
import mockit.asm.jvmConstants.Access;
27
import mockit.asm.metadata.ClassMetadataReader;
28
import mockit.asm.metadata.ClassMetadataReader.MethodInfo;
29
import mockit.asm.methods.MethodVisitor;
30
import mockit.asm.types.JavaType;
31
import mockit.internal.BaseClassModifier;
32
import mockit.internal.ClassFile;
33
import mockit.internal.util.TypeDescriptor;
34

35
public class BaseSubclassGenerator extends BaseClassModifier {
36
    private static final int CLASS_ACCESS_MASK = 0xFFFF - Access.ABSTRACT;
37
    private static final int CONSTRUCTOR_ACCESS_MASK = Access.PUBLIC + Access.PROTECTED;
38

39
    // Fixed initial state:
40
    @NonNull
41
    Class<?> baseClass;
42
    @NonNull
43
    private final String subclassName;
44
    @Nullable
45
    protected final MockedTypeInfo mockedTypeInfo;
46
    private final boolean copyConstructors;
47

48
    // Helper fields for mutable state:
49
    @NonNull
50
    private final List<String> implementedMethods;
51
    @Nullable
52
    private String superClassOfSuperClass;
53
    private Set<String> superInterfaces;
54

55
    protected BaseSubclassGenerator(@NonNull Class<?> baseClass, @NonNull ClassReader cr,
56
            @Nullable Type genericMockedType, @NonNull String subclassName, boolean copyConstructors) {
57
        super(cr);
1✔
58
        this.baseClass = baseClass;
1✔
59
        this.subclassName = subclassName.replace('.', '/');
1✔
60
        mockedTypeInfo = genericMockedType == null ? null : new MockedTypeInfo(genericMockedType);
1✔
61
        this.copyConstructors = copyConstructors;
1✔
62
        implementedMethods = new ArrayList<>();
1✔
63
    }
1✔
64

65
    @Override
66
    public void visit(int version, int access, @NonNull String name, @NonNull ClassInfo additionalInfo) {
67
        ClassInfo subClassInfo = new ClassInfo();
1✔
68
        subClassInfo.superName = name;
1✔
69
        subClassInfo.signature = mockedTypeInfo == null ? additionalInfo.signature
1✔
70
                : mockedTypeInfo.implementationSignature;
1✔
71
        int subclassAccess = access & CLASS_ACCESS_MASK | Access.FINAL;
1✔
72

73
        super.visit(version, subclassAccess, subclassName, subClassInfo);
1✔
74

75
        superClassOfSuperClass = additionalInfo.superName;
1✔
76
        superInterfaces = new HashSet<>();
1✔
77

78
        String[] interfaces = additionalInfo.interfaces;
1✔
79

80
        if (interfaces.length > 0) {
1✔
81
            superInterfaces.addAll(asList(interfaces));
1✔
82
        }
83
    }
1✔
84

85
    @Override
86
    public final void visitInnerClass(@NonNull String name, @Nullable String outerName, @Nullable String innerName,
87
            int access) {
88
    }
1✔
89

90
    @Override
91
    @Nullable
92
    public final FieldVisitor visitField(int access, @NonNull String name, @NonNull String desc,
93
            @Nullable String signature, @Nullable Object value) {
94
        return null;
1✔
95
    }
96

97
    @Override
98
    @Nullable
99
    public MethodVisitor visitMethod(int access, @NonNull String name, @NonNull String desc, @Nullable String signature,
100
            @Nullable String[] exceptions) {
101
        if (copyConstructors && "<init>".equals(name)) {
1✔
102
            if ((access & CONSTRUCTOR_ACCESS_MASK) != 0) {
1!
103
                generateConstructorDelegatingToSuper(desc, signature, exceptions);
1✔
104
            }
105
        } else {
106
            // Inherits from super-class when non-abstract; otherwise, creates implementation for abstract method.
107
            generateImplementationIfAbstractMethod(superClassName, access, name, desc, signature, exceptions);
1✔
108
        }
109

110
        return null;
1✔
111
    }
112

113
    private void generateConstructorDelegatingToSuper(@NonNull String desc, @Nullable String signature,
114
            @Nullable String[] exceptions) {
115
        mw = cw.visitMethod(Access.PUBLIC, "<init>", desc, signature, exceptions);
1✔
116
        mw.visitVarInsn(ALOAD, 0);
1✔
117
        int varIndex = 1;
1✔
118

119
        for (JavaType paramType : JavaType.getArgumentTypes(desc)) {
1✔
120
            int loadOpcode = paramType.getLoadOpcode();
1✔
121
            mw.visitVarInsn(loadOpcode, varIndex);
1✔
122
            varIndex++;
1✔
123
        }
124

125
        mw.visitMethodInsn(INVOKESPECIAL, superClassName, "<init>", desc, false);
1✔
126
        generateEmptyImplementation();
1✔
127
    }
1✔
128

129
    private void generateImplementationIfAbstractMethod(String className, int access, @NonNull String name,
130
            @NonNull String desc, @Nullable String signature, @Nullable String[] exceptions) {
131
        if (!"<init>".equals(name)) {
1✔
132
            String methodNameAndDesc = name + desc;
1✔
133

134
            if (!implementedMethods.contains(methodNameAndDesc)) {
1✔
135
                if ((access & Access.ABSTRACT) != 0) {
1✔
136
                    generateMethodImplementation(className, access, name, desc, signature, exceptions);
1✔
137
                }
138

139
                implementedMethods.add(methodNameAndDesc);
1✔
140
            }
141
        }
142
    }
1✔
143

144
    protected void generateMethodImplementation(String className, int access, @NonNull String name,
145
            @NonNull String desc, @Nullable String signature, @Nullable String[] exceptions) {
146
    }
×
147

148
    @Override
149
    public void visitEnd() {
150
        generateImplementationsForInheritedAbstractMethods(superClassOfSuperClass);
1✔
151

152
        while (!superInterfaces.isEmpty()) {
1✔
153
            String superInterface = superInterfaces.iterator().next();
1✔
154
            generateImplementationsForAbstractMethods(superInterface, false);
1✔
155
            superInterfaces.remove(superInterface);
1✔
156
        }
1✔
157
    }
1✔
158

159
    private void generateImplementationsForInheritedAbstractMethods(@Nullable String superName) {
160
        if (superName != null) {
1!
161
            generateImplementationsForAbstractMethods(superName, true);
1✔
162
        }
163
    }
1✔
164

165
    private void generateImplementationsForAbstractMethods(@NonNull String typeName, boolean abstractClass) {
166
        if (!"java/lang/Object".equals(typeName)) {
1✔
167
            byte[] typeBytecode = ClassFile.getClassFile(typeName);
1✔
168
            ClassMetadataReader cmr = new ClassMetadataReader(typeBytecode);
1✔
169
            String[] interfaces = cmr.getInterfaces();
1✔
170

171
            if (interfaces != null) {
1✔
172
                superInterfaces.addAll(asList(interfaces));
1✔
173
            }
174

175
            for (MethodInfo method : cmr.getMethods()) {
1✔
176
                if (abstractClass) {
1✔
177
                    generateImplementationIfAbstractMethod(typeName, method.accessFlags, method.name, method.desc, null,
1✔
178
                            null);
179
                } else if (method.isAbstract()) {
1✔
180
                    generateImplementationForInterfaceMethodIfMissing(typeName, method);
1✔
181
                }
182
            }
1✔
183

184
            if (abstractClass) {
1✔
185
                String superClass = cmr.getSuperClass();
1✔
186
                generateImplementationsForInheritedAbstractMethods(superClass);
1✔
187
            }
188
        }
189
    }
1✔
190

191
    private void generateImplementationForInterfaceMethodIfMissing(@NonNull String typeName,
192
            @NonNull MethodInfo method) {
193
        String name = method.name;
1✔
194
        String desc = method.desc;
1✔
195
        String methodNameAndDesc = name + desc;
1✔
196

197
        if (!implementedMethods.contains(methodNameAndDesc)) {
1✔
198
            if (!hasMethodImplementation(name, desc)) {
1!
199
                generateMethodImplementation(typeName, method.accessFlags, name, desc, null, null);
1✔
200
            }
201

202
            implementedMethods.add(methodNameAndDesc);
1✔
203
        }
204
    }
1✔
205

206
    private boolean hasMethodImplementation(@NonNull String name, @NonNull String desc) {
207
        Class<?>[] paramTypes = TypeDescriptor.getParameterTypes(desc);
1✔
208

209
        try {
210
            Method method = baseClass.getMethod(name, paramTypes);
1✔
211
            return !method.getDeclaringClass().isInterface();
1!
212
        } catch (NoSuchMethodException ignore) {
×
213
            return false;
×
214
        }
215
    }
216
}
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