View Javadoc
1   /*
2    * MIT License
3    * Copyright (c) 2006-2025 JMockit developers
4    * See LICENSE file for full license text.
5    */
6   package mockit.internal.faking;
7   
8   import static java.lang.reflect.Modifier.isPublic;
9   
10  import edu.umd.cs.findbugs.annotations.NonNull;
11  import edu.umd.cs.findbugs.annotations.Nullable;
12  
13  import java.lang.reflect.Proxy;
14  import java.lang.reflect.Type;
15  
16  import mockit.MockUp;
17  import mockit.asm.classes.ClassReader;
18  import mockit.asm.classes.ClassVisitor;
19  import mockit.internal.classGeneration.ImplementationClass;
20  import mockit.internal.expectations.mocking.InterfaceImplementationGenerator;
21  import mockit.internal.util.Utilities;
22  
23  public final class FakedImplementationClass<T> {
24      private static final ClassLoader THIS_CL = FakedImplementationClass.class.getClassLoader();
25  
26      @NonNull
27      private final MockUp<?> fakeInstance;
28      @Nullable
29      private ImplementationClass<T> implementationClass;
30      private Class<T> generatedClass;
31  
32      public FakedImplementationClass(@NonNull MockUp<?> fakeInstance) {
33          this.fakeInstance = fakeInstance;
34      }
35  
36      @NonNull
37      public Class<T> createImplementation(@NonNull Class<T> interfaceToBeFaked, @Nullable Type typeToFake) {
38          createImplementation(interfaceToBeFaked);
39          byte[] generatedBytecode = implementationClass == null ? null : implementationClass.getGeneratedBytecode();
40  
41          FakeClassSetup fakeClassSetup = new FakeClassSetup(generatedClass, typeToFake, fakeInstance, generatedBytecode);
42          fakeClassSetup.redefineMethodsInGeneratedClass();
43  
44          return generatedClass;
45      }
46  
47      @NonNull
48      Class<T> createImplementation(@NonNull Class<T> interfaceToBeFaked) {
49          if (isPublic(interfaceToBeFaked.getModifiers())) {
50              generateImplementationForPublicInterface(interfaceToBeFaked);
51          } else {
52              // noinspection unchecked
53              generatedClass = (Class<T>) Proxy.getProxyClass(interfaceToBeFaked.getClassLoader(), interfaceToBeFaked);
54          }
55  
56          return generatedClass;
57      }
58  
59      private void generateImplementationForPublicInterface(@NonNull Class<T> interfaceToBeFaked) {
60          implementationClass = new ImplementationClass<T>(interfaceToBeFaked) {
61              @NonNull
62              @Override
63              protected ClassVisitor createMethodBodyGenerator(@NonNull ClassReader typeReader) {
64                  return new InterfaceImplementationGenerator(typeReader, interfaceToBeFaked, generatedClassName);
65              }
66          };
67  
68          generatedClass = implementationClass.generateClass();
69      }
70  
71      @NonNull
72      public Class<T> createImplementation(@NonNull Type[] interfacesToBeFaked) {
73          Class<?>[] interfacesToFake = new Class<?>[interfacesToBeFaked.length];
74  
75          for (int i = 0; i < interfacesToFake.length; i++) {
76              interfacesToFake[i] = Utilities.getClassType(interfacesToBeFaked[i]);
77          }
78  
79          // noinspection unchecked
80          generatedClass = (Class<T>) Proxy.getProxyClass(THIS_CL, interfacesToFake);
81          new FakeClassSetup(generatedClass, null, fakeInstance, null).redefineMethods();
82  
83          return generatedClass;
84      }
85  }