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