1
2
3
4
5 package mockit.internal.capturing;
6
7 import edu.umd.cs.findbugs.annotations.NonNull;
8 import edu.umd.cs.findbugs.annotations.Nullable;
9
10 import mockit.asm.classes.ClassReader;
11 import mockit.internal.BaseClassModifier;
12 import mockit.internal.ClassFile;
13 import mockit.internal.startup.Startup;
14 import mockit.internal.state.TestRun;
15
16 public abstract class CaptureOfImplementations<M> {
17 protected CaptureOfImplementations() {
18 }
19
20 protected final void makeSureAllSubtypesAreModified(@NonNull Class<?> baseType, boolean registerCapturedClasses,
21 @Nullable M typeMetadata) {
22 CapturedType captureMetadata = new CapturedType(baseType);
23 redefineClassesAlreadyLoaded(captureMetadata, baseType, typeMetadata);
24 createCaptureTransformer(captureMetadata, registerCapturedClasses, typeMetadata);
25 }
26
27 private void redefineClassesAlreadyLoaded(@NonNull CapturedType captureMetadata, @NonNull Class<?> baseType,
28 @Nullable M typeMetadata) {
29 Class<?>[] classesLoaded = Startup.instrumentation().getAllLoadedClasses();
30
31 for (Class<?> aClass : classesLoaded) {
32 if (captureMetadata.isToBeCaptured(aClass)) {
33 redefineClass(aClass, baseType, typeMetadata);
34 }
35 }
36 }
37
38 protected final void redefineClass(@NonNull Class<?> realClass, @NonNull Class<?> baseType,
39 @Nullable M typeMetadata) {
40 if (!TestRun.mockFixture().containsRedefinedClass(realClass)) {
41 ClassReader classReader;
42
43 try {
44 classReader = ClassFile.createReaderOrGetFromCache(realClass);
45 } catch (ClassFile.NotFoundException ignore) {
46 return;
47 }
48
49 TestRun.ensureThatClassIsInitialized(realClass);
50
51 BaseClassModifier modifier = createModifier(realClass.getClassLoader(), classReader, baseType,
52 typeMetadata);
53 classReader.accept(modifier);
54
55 if (modifier.wasModified()) {
56 byte[] modifiedClass = modifier.toByteArray();
57 redefineClass(realClass, modifiedClass);
58 }
59 }
60 }
61
62 @NonNull
63 protected abstract BaseClassModifier createModifier(@Nullable ClassLoader cl, @NonNull ClassReader cr,
64 @NonNull Class<?> baseType, @Nullable M typeMetadata);
65
66 protected abstract void redefineClass(@NonNull Class<?> realClass, @NonNull byte[] modifiedClass);
67
68 private void createCaptureTransformer(@NonNull CapturedType captureMetadata, boolean registerCapturedClasses,
69 @Nullable M typeMetadata) {
70 CaptureTransformer<M> transformer = new CaptureTransformer<>(captureMetadata, this, registerCapturedClasses,
71 typeMetadata);
72 Startup.instrumentation().addTransformer(transformer, true);
73 TestRun.mockFixture().addCaptureTransformer(transformer);
74 }
75 }