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