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