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