1
2
3
4
5
6 package mockit.internal.startup;
7
8 import static java.lang.reflect.Modifier.PUBLIC;
9 import static java.lang.reflect.Modifier.STATIC;
10 import static java.lang.reflect.Modifier.isPublic;
11
12 import edu.umd.cs.findbugs.annotations.NonNull;
13 import edu.umd.cs.findbugs.annotations.Nullable;
14
15 import java.lang.instrument.ClassFileTransformer;
16 import java.lang.instrument.Instrumentation;
17 import java.security.ProtectionDomain;
18 import java.security.Provider;
19
20 import mockit.asm.classes.ClassReader;
21 import mockit.asm.classes.ClassVisitor;
22 import mockit.asm.classes.ClassWriter;
23 import mockit.asm.classes.WrappingClassVisitor;
24 import mockit.asm.jvmConstants.Access;
25 import mockit.internal.ClassLoadingBridge;
26 import mockit.internal.expectations.mocking.MockedBridge;
27 import mockit.internal.faking.FakeBridge;
28 import mockit.internal.faking.FakeMethodBridge;
29
30 final class ClassLoadingBridgeFields {
31 private ClassLoadingBridgeFields() {
32 }
33
34 static void createSyntheticFieldsInJREClassToHoldClassLoadingBridges(@NonNull Instrumentation instrumentation) {
35 FieldAdditionTransformer fieldAdditionTransformer = new FieldAdditionTransformer(instrumentation);
36 instrumentation.addTransformer(fieldAdditionTransformer);
37
38
39 NegativeArraySizeException.class.getName();
40 String hostClassName = fieldAdditionTransformer.hostClassName;
41
42 if (hostClassName == null) {
43 Provider.class.getName();
44 hostClassName = fieldAdditionTransformer.hostClassName;
45 }
46
47 ClassLoadingBridge.hostJREClassName = hostClassName;
48 }
49
50 private static final class FieldAdditionTransformer implements ClassFileTransformer {
51 private static final int FIELD_ACCESS = PUBLIC + STATIC + Access.SYNTHETIC;
52 @NonNull
53 private final Instrumentation instrumentation;
54 String hostClassName;
55
56 FieldAdditionTransformer(@NonNull Instrumentation instrumentation) {
57 this.instrumentation = instrumentation;
58 }
59
60 @Nullable
61 @Override
62 public byte[] transform(@Nullable ClassLoader loader, @NonNull String className,
63 @Nullable Class<?> classBeingRedefined, @Nullable ProtectionDomain protectionDomain,
64 @NonNull byte[] classfileBuffer) {
65 if (loader == null && hostClassName == null) {
66 ClassReader cr = new ClassReader(classfileBuffer);
67
68 if (isPublic(cr.getAccess())) {
69 instrumentation.removeTransformer(this);
70 hostClassName = className;
71 return getModifiedJREClassWithAddedFields(cr);
72 }
73 }
74
75 return null;
76 }
77
78 @NonNull
79 private static byte[] getModifiedJREClassWithAddedFields(@NonNull ClassReader classReader) {
80 ClassWriter cw = new ClassWriter(classReader);
81
82 ClassVisitor cv = new WrappingClassVisitor(cw) {
83 @Override
84 public void visitEnd() {
85 addField(MockedBridge.MB);
86 addField(FakeBridge.MB);
87 addField(FakeMethodBridge.MB);
88 }
89
90 private void addField(@NonNull ClassLoadingBridge mb) {
91 cw.visitField(FIELD_ACCESS, mb.id, "Ljava/lang/reflect/InvocationHandler;", null, null);
92 }
93 };
94
95 classReader.accept(cv);
96 return cw.toByteArray();
97 }
98 }
99 }