1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.jxpath.util;
19
20 import java.lang.reflect.Constructor;
21 import java.lang.reflect.Method;
22 import java.lang.reflect.Modifier;
23 import java.util.Arrays;
24
25 import org.apache.commons.jxpath.ExpressionContext;
26 import org.apache.commons.jxpath.JXPathException;
27
28
29
30
31 public class MethodLookupUtils {
32
33 private static final int NO_MATCH = 0;
34 private static final int APPROXIMATE_MATCH = 1;
35 private static final int EXACT_MATCH = 2;
36
37
38
39
40
41
42
43
44 public static Constructor lookupConstructor(final Class targetClass, final Object[] parameters) {
45 boolean tryExact = true;
46 final int count = parameters == null ? 0 : parameters.length;
47 final Class[] types = new Class[count];
48 for (int i = 0; i < count; i++) {
49 final Object param = parameters[i];
50 if (param != null) {
51 types[i] = param.getClass();
52 } else {
53 types[i] = null;
54 tryExact = false;
55 }
56 }
57 Constructor constructor = null;
58 if (tryExact) {
59
60 try {
61 constructor = targetClass.getConstructor(types);
62 if (constructor != null) {
63 return constructor;
64 }
65 } catch (final NoSuchMethodException ignore) {
66
67 }
68 }
69 int currentMatch = 0;
70 boolean ambiguous = false;
71
72 final Constructor[] constructors = targetClass.getConstructors();
73 for (final Constructor constructor2 : constructors) {
74 final int match = matchParameterTypes(constructor2.getParameterTypes(), parameters);
75 if (match != NO_MATCH) {
76 if (match > currentMatch) {
77 constructor = constructor2;
78 currentMatch = match;
79 ambiguous = false;
80 } else if (match == currentMatch) {
81 ambiguous = true;
82 }
83 }
84 }
85 if (ambiguous) {
86 throw new JXPathException("Ambiguous constructor " + Arrays.asList(parameters));
87 }
88 return constructor;
89 }
90
91
92
93
94
95
96
97
98
99 public static Method lookupMethod(Class targetClass, final String name, final Object[] parameters) {
100 if (parameters == null || parameters.length < 1 || parameters[0] == null) {
101 return null;
102 }
103 if (matchType(targetClass, parameters[0]) == NO_MATCH) {
104 return null;
105 }
106 targetClass = TypeUtils.convert(parameters[0], targetClass).getClass();
107 boolean tryExact = true;
108 final int count = parameters.length - 1;
109 final Class[] types = new Class[count];
110 final Object[] arguments = new Object[count];
111 for (int i = 0; i < count; i++) {
112 final Object param = parameters[i + 1];
113 arguments[i] = param;
114 if (param != null) {
115 types[i] = param.getClass();
116 } else {
117 types[i] = null;
118 tryExact = false;
119 }
120 }
121 Method method = null;
122 if (tryExact) {
123
124 try {
125 method = targetClass.getMethod(name, types);
126 if (method != null && !Modifier.isStatic(method.getModifiers())) {
127 return method;
128 }
129 } catch (final NoSuchMethodException ignore) {
130
131 }
132 }
133 int currentMatch = 0;
134 boolean ambiguous = false;
135
136 final Method[] methods = targetClass.getMethods();
137 for (final Method method2 : methods) {
138 if (!Modifier.isStatic(method2.getModifiers()) && method2.getName().equals(name)) {
139 final int match = matchParameterTypes(method2.getParameterTypes(), arguments);
140 if (match != NO_MATCH) {
141 if (match > currentMatch) {
142 method = method2;
143 currentMatch = match;
144 ambiguous = false;
145 } else if (match == currentMatch) {
146 ambiguous = true;
147 }
148 }
149 }
150 }
151 if (ambiguous) {
152 throw new JXPathException("Ambiguous method call: " + name);
153 }
154 return method;
155 }
156
157
158
159
160
161
162
163
164
165 public static Method lookupStaticMethod(final Class targetClass, final String name, final Object[] parameters) {
166 boolean tryExact = true;
167 final int count = parameters == null ? 0 : parameters.length;
168 final Class[] types = new Class[count];
169 for (int i = 0; i < count; i++) {
170 final Object param = parameters[i];
171 if (param != null) {
172 types[i] = param.getClass();
173 } else {
174 types[i] = null;
175 tryExact = false;
176 }
177 }
178 Method method = null;
179 if (tryExact) {
180
181 try {
182 method = targetClass.getMethod(name, types);
183 if (method != null && Modifier.isStatic(method.getModifiers())) {
184 return method;
185 }
186 } catch (final NoSuchMethodException ignore) {
187
188 }
189 }
190 int currentMatch = 0;
191 boolean ambiguous = false;
192
193 final Method[] methods = targetClass.getMethods();
194 for (final Method method2 : methods) {
195 if (Modifier.isStatic(method2.getModifiers()) && method2.getName().equals(name)) {
196 final int match = matchParameterTypes(method2.getParameterTypes(), parameters);
197 if (match != NO_MATCH) {
198 if (match > currentMatch) {
199 method = method2;
200 currentMatch = match;
201 ambiguous = false;
202 } else if (match == currentMatch) {
203 ambiguous = true;
204 }
205 }
206 }
207 }
208 if (ambiguous) {
209 throw new JXPathException("Ambiguous method call: " + name);
210 }
211 return method;
212 }
213
214
215
216
217
218
219
220
221 private static int matchParameterTypes(final Class[] types, final Object[] parameters) {
222 int pi = 0;
223 if (types.length >= 1 && ExpressionContext.class.isAssignableFrom(types[0])) {
224 pi++;
225 }
226 final int length = parameters == null ? 0 : parameters.length;
227 if (types.length != length + pi) {
228 return NO_MATCH;
229 }
230 int totalMatch = EXACT_MATCH;
231 for (int i = 0; i < length; i++) {
232 final int match = matchType(types[i + pi], parameters[i]);
233 if (match == NO_MATCH) {
234 return NO_MATCH;
235 }
236 if (match < totalMatch) {
237 totalMatch = match;
238 }
239 }
240 return totalMatch;
241 }
242
243
244
245
246
247
248
249
250 private static int matchType(final Class expected, final Object object) {
251 if (object == null) {
252 return APPROXIMATE_MATCH;
253 }
254 final Class actual = object.getClass();
255 if (expected.equals(actual)) {
256 return EXACT_MATCH;
257 }
258 if (expected.isAssignableFrom(actual)) {
259 return EXACT_MATCH;
260 }
261 if (TypeUtils.canConvert(object, expected)) {
262 return APPROXIMATE_MATCH;
263 }
264 return NO_MATCH;
265 }
266
267
268
269
270
271
272 @Deprecated
273 public MethodLookupUtils() {
274
275 }
276 }