View Javadoc
1   /*
2    * Copyright (c) 2006 JMockit developers
3    * This file is subject to the terms of the MIT license (see LICENSE.txt).
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          // Loads some JRE classes expected to not be loaded yet.
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) { // adds the fields to the first public JRE class to be loaded
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  }