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.reflection;
6   
7   import edu.umd.cs.findbugs.annotations.NonNull;
8   import edu.umd.cs.findbugs.annotations.Nullable;
9   
10  import java.lang.reflect.Constructor;
11  import java.lang.reflect.Member;
12  import java.lang.reflect.Method;
13  
14  import mockit.internal.util.ClassLoad;
15  import mockit.internal.util.TypeDescriptor;
16  
17  public final class RealMethodOrConstructor {
18      @NonNull
19      public final Member member;
20  
21      public RealMethodOrConstructor(@NonNull String className, @NonNull String memberNameAndDesc)
22              throws NoSuchMethodException {
23          this(ClassLoad.loadFromLoader(RealMethodOrConstructor.class.getClassLoader(), className), memberNameAndDesc);
24      }
25  
26      public RealMethodOrConstructor(@NonNull Class<?> realClass, @NonNull String memberNameAndDesc)
27              throws NoSuchMethodException {
28          int p = memberNameAndDesc.indexOf('(');
29          String memberDesc = memberNameAndDesc.substring(p);
30  
31          if (memberNameAndDesc.charAt(0) == '<') {
32              member = findConstructor(realClass, memberDesc);
33          } else {
34              String methodName = memberNameAndDesc.substring(0, p);
35              member = findMethod(realClass, methodName, memberDesc);
36          }
37      }
38  
39      public RealMethodOrConstructor(@NonNull Class<?> realClass, @NonNull String memberName, @NonNull String memberDesc)
40              throws NoSuchMethodException {
41          if (memberName.charAt(0) == '<') {
42              member = findConstructor(realClass, memberDesc);
43          } else {
44              member = findMethod(realClass, memberName, memberDesc);
45          }
46      }
47  
48      @NonNull
49      private static Constructor<?> findConstructor(@NonNull Class<?> realClass, @NonNull String constructorDesc) {
50          Class<?>[] parameterTypes = TypeDescriptor.getParameterTypes(constructorDesc);
51          return ConstructorReflection.findSpecifiedConstructor(realClass, parameterTypes);
52      }
53  
54      @NonNull
55      private static Method findMethod(@NonNull Class<?> realClass, @NonNull String methodName,
56              @NonNull String methodDesc) throws NoSuchMethodException {
57          Class<?>[] parameterTypes = TypeDescriptor.getParameterTypes(methodDesc);
58          Class<?> ownerClass = realClass;
59  
60          while (true) {
61              try {
62                  Method method = ownerClass.getDeclaredMethod(methodName, parameterTypes);
63  
64                  if (method.isBridge()) {
65                      ownerClass = ownerClass.getSuperclass();
66                      continue;
67                  }
68  
69                  return method;
70              } catch (NoSuchMethodException e) {
71                  Method interfaceMethod = findInterfaceMethod(ownerClass, methodName, parameterTypes);
72  
73                  if (interfaceMethod != null) {
74                      return interfaceMethod;
75                  }
76  
77                  ownerClass = ownerClass.getSuperclass();
78  
79                  if (ownerClass == null || ownerClass == Object.class) {
80                      throw e;
81                  }
82              }
83          }
84      }
85  
86      @Nullable
87      private static Method findInterfaceMethod(@NonNull Class<?> aType, @NonNull String methodName,
88              @NonNull Class<?>[] parameterTypes) {
89          for (Class<?> anInterface : aType.getInterfaces()) {
90              try {
91                  return anInterface.getMethod(methodName, parameterTypes);
92              } catch (NoSuchMethodException ignore) {
93              }
94          }
95  
96          return null;
97      }
98  
99      @NonNull
100     public <M extends Member> M getMember() {
101         // noinspection unchecked
102         return (M) member;
103     }
104 }