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 mockit.asm.jvmConstants.Access.ABSTRACT;
8   import static mockit.asm.jvmConstants.Access.BRIDGE;
9   import static mockit.asm.jvmConstants.Access.NATIVE;
10  import static mockit.asm.jvmConstants.Access.SYNTHETIC;
11  
12  import edu.umd.cs.findbugs.annotations.NonNull;
13  
14  import java.util.EnumSet;
15  import java.util.List;
16  
17  import mockit.Mock;
18  import mockit.MockUp;
19  import mockit.asm.metadata.ClassMetadataReader;
20  import mockit.asm.metadata.ClassMetadataReader.Attribute;
21  import mockit.asm.metadata.ClassMetadataReader.MethodInfo;
22  import mockit.asm.types.JavaType;
23  import mockit.internal.ClassFile;
24  import mockit.internal.faking.FakeMethods.FakeMethod;
25  import mockit.internal.util.ClassLoad;
26  
27  /**
28   * Responsible for collecting the signatures of all methods defined in a given fake class which are explicitly annotated
29   * as {@link Mock fakes}.
30   */
31  final class FakeMethodCollector {
32      private static final int INVALID_METHOD_ACCESSES = BRIDGE + SYNTHETIC + ABSTRACT + NATIVE;
33      private static final EnumSet<Attribute> ANNOTATIONS = EnumSet.of(Attribute.Annotations);
34  
35      @NonNull
36      private final FakeMethods fakeMethods;
37      private boolean collectingFromSuperClass;
38  
39      FakeMethodCollector(@NonNull FakeMethods fakeMethods) {
40          this.fakeMethods = fakeMethods;
41      }
42  
43      void collectFakeMethods(@NonNull Class<?> fakeClass) {
44          ClassLoad.registerLoadedClass(fakeClass);
45          fakeMethods.setFakeClassInternalName(JavaType.getInternalName(fakeClass));
46  
47          Class<?> classToCollectFakesFrom = fakeClass;
48  
49          do {
50              byte[] classfileBytes = ClassFile.readBytesFromClassFile(classToCollectFakesFrom);
51              ClassMetadataReader cmr = new ClassMetadataReader(classfileBytes, ANNOTATIONS);
52              List<MethodInfo> methods = cmr.getMethods();
53              addFakeMethods(methods);
54  
55              classToCollectFakesFrom = classToCollectFakesFrom.getSuperclass();
56              collectingFromSuperClass = true;
57          } while (classToCollectFakesFrom != MockUp.class);
58      }
59  
60      private void addFakeMethods(@NonNull List<MethodInfo> methods) {
61          for (MethodInfo method : methods) {
62              int access = method.accessFlags;
63  
64              if ((access & INVALID_METHOD_ACCESSES) == 0 && method.isMethod() && method.hasAnnotation("Lmockit/Mock;")) {
65                  FakeMethod fakeMethod = fakeMethods.addMethod(collectingFromSuperClass, access, method.name,
66                          method.desc);
67  
68                  if (fakeMethod != null && fakeMethod.requiresFakeState()) {
69                      FakeState fakeState = new FakeState(fakeMethod);
70                      fakeMethods.addFakeState(fakeState);
71                  }
72              }
73          }
74      }
75  }