1
2
3
4
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
103 return (M) member;
104 }
105 }