1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.shared.utils.introspection;
20
21 import java.lang.reflect.Method;
22 import java.util.ArrayList;
23 import java.util.Hashtable;
24 import java.util.Iterator;
25 import java.util.LinkedList;
26 import java.util.List;
27 import java.util.Map;
28
29
30
31
32
33
34
35
36
37 class MethodMap {
38 private static final int MORE_SPECIFIC = 0;
39
40 private static final int LESS_SPECIFIC = 1;
41
42 private static final int INCOMPARABLE = 2;
43
44
45
46
47 private final Map<String, List<Method>> methodByNameMap = new Hashtable<String, List<Method>>();
48
49
50
51
52
53
54
55
56 void add(Method method) {
57 String methodName = method.getName();
58
59 List<Method> l = get(methodName);
60
61 if (l == null) {
62 l = new ArrayList<Method>();
63 methodByNameMap.put(methodName, l);
64 }
65
66 l.add(method);
67 }
68
69
70
71
72
73
74
75 List<Method> get(String key) {
76 return methodByNameMap.get(key);
77 }
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107 Method find(String methodName, Object... args) throws AmbiguousException {
108 List<Method> methodList = get(methodName);
109
110 if (methodList == null) {
111 return null;
112 }
113
114 int l = args.length;
115 Class<?>[] classes = new Class[l];
116
117 for (int i = 0; i < l; ++i) {
118 Object arg = args[i];
119
120
121
122
123
124 classes[i] = arg == null ? null : arg.getClass();
125 }
126
127 return getMostSpecific(methodList, classes);
128 }
129
130
131
132
133
134 static class AmbiguousException extends Exception {
135
136 private static final long serialVersionUID = 751688436639650618L;
137 }
138
139 private static Method getMostSpecific(List<Method> methods, Class<?>... classes) throws AmbiguousException {
140 LinkedList<Method> applicables = getApplicables(methods, classes);
141
142 if (applicables.isEmpty()) {
143 return null;
144 }
145
146 if (applicables.size() == 1) {
147 return applicables.getFirst();
148 }
149
150
151
152
153
154
155
156 LinkedList<Method> maximals = new LinkedList<Method>();
157
158 for (Method app : applicables) {
159 Class<?>[] appArgs = app.getParameterTypes();
160 boolean lessSpecific = false;
161
162 for (Iterator<Method> maximal = maximals.iterator(); !lessSpecific && maximal.hasNext(); ) {
163 Method max = maximal.next();
164
165 switch (moreSpecific(appArgs, max.getParameterTypes())) {
166 case MORE_SPECIFIC:
167
168
169
170
171
172 maximal.remove();
173 break;
174
175 case LESS_SPECIFIC:
176
177
178
179
180
181
182
183 lessSpecific = true;
184 break;
185
186 default:
187 }
188 }
189
190 if (!lessSpecific) {
191 maximals.addLast(app);
192 }
193 }
194
195 if (maximals.size() > 1) {
196
197 throw new AmbiguousException();
198 }
199
200 return maximals.getFirst();
201 }
202
203
204
205
206
207
208
209
210
211
212 private static int moreSpecific(Class<?>[] c1, Class<?>[] c2) {
213 boolean c1MoreSpecific = false;
214 boolean c2MoreSpecific = false;
215
216 for (int i = 0; i < c1.length; ++i) {
217 if (c1[i] != c2[i]) {
218 c1MoreSpecific = c1MoreSpecific || isStrictMethodInvocationConvertible(c2[i], c1[i]);
219 c2MoreSpecific = c2MoreSpecific || isStrictMethodInvocationConvertible(c1[i], c2[i]);
220 }
221 }
222
223 if (c1MoreSpecific) {
224 if (c2MoreSpecific) {
225
226
227
228
229
230 return INCOMPARABLE;
231 }
232
233 return MORE_SPECIFIC;
234 }
235
236 if (c2MoreSpecific) {
237 return LESS_SPECIFIC;
238 }
239
240
241
242
243
244
245 return INCOMPARABLE;
246 }
247
248
249
250
251
252
253
254
255
256
257 private static LinkedList<Method> getApplicables(List<Method> methods, Class<?>... classes) {
258 LinkedList<Method> list = new LinkedList<Method>();
259
260 for (Method method : methods) {
261 if (isApplicable(method, classes)) {
262 list.add(method);
263 }
264 }
265 return list;
266 }
267
268
269
270
271
272
273
274
275
276 private static boolean isApplicable(Method method, Class<?>... classes) {
277 Class<?>[] methodArgs = method.getParameterTypes();
278
279 if (methodArgs.length != classes.length) {
280 return false;
281 }
282
283 for (int i = 0; i < classes.length; ++i) {
284 if (!isMethodInvocationConvertible(methodArgs[i], classes[i])) {
285 return false;
286 }
287 }
288
289 return true;
290 }
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310 private static boolean isMethodInvocationConvertible(Class<?> formal, Class<?> actual) {
311
312
313
314 if (actual == null && !formal.isPrimitive()) {
315 return true;
316 }
317
318
319
320
321
322 if (actual != null && formal.isAssignableFrom(actual)) {
323 return true;
324 }
325
326
327
328
329
330
331 if (formal.isPrimitive()) {
332 if (formal == Boolean.TYPE && actual == Boolean.class) {
333 return true;
334 }
335 if (formal == Character.TYPE && actual == Character.class) {
336 return true;
337 }
338 if (formal == Byte.TYPE && actual == Byte.class) {
339 return true;
340 }
341 if (formal == Short.TYPE && (actual == Short.class || actual == Byte.class)) {
342 return true;
343 }
344 if (formal == Integer.TYPE && (actual == Integer.class || actual == Short.class || actual == Byte.class)) {
345 return true;
346 }
347 if (formal == Long.TYPE
348 && (actual == Long.class
349 || actual == Integer.class
350 || actual == Short.class
351 || actual == Byte.class)) {
352 return true;
353 }
354 if (formal == Float.TYPE
355 && (actual == Float.class
356 || actual == Long.class
357 || actual == Integer.class
358 || actual == Short.class
359 || actual == Byte.class)) {
360 return true;
361 }
362 if (formal == Double.TYPE
363 && (actual == Double.class
364 || actual == Float.class
365 || actual == Long.class
366 || actual == Integer.class
367 || actual == Short.class
368 || actual == Byte.class)) {
369 return true;
370 }
371 }
372
373 return false;
374 }
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390 private static boolean isStrictMethodInvocationConvertible(Class<?> formal, Class<?> actual) {
391
392
393
394 if (actual == null && !formal.isPrimitive()) {
395 return true;
396 }
397
398
399
400
401
402 if (formal.isAssignableFrom(actual)) {
403 return true;
404 }
405
406
407
408
409
410 if (formal.isPrimitive()) {
411 if (formal == Short.TYPE && (actual == Byte.TYPE)) {
412 return true;
413 }
414 if (formal == Integer.TYPE && (actual == Short.TYPE || actual == Byte.TYPE)) {
415 return true;
416 }
417 if (formal == Long.TYPE && (actual == Integer.TYPE || actual == Short.TYPE || actual == Byte.TYPE)) {
418 return true;
419 }
420 if (formal == Float.TYPE
421 && (actual == Long.TYPE || actual == Integer.TYPE || actual == Short.TYPE || actual == Byte.TYPE)) {
422 return true;
423 }
424 if (formal == Double.TYPE
425 && (actual == Float.TYPE
426 || actual == Long.TYPE
427 || actual == Integer.TYPE
428 || actual == Short.TYPE
429 || actual == Byte.TYPE)) {
430 return true;
431 }
432 }
433 return false;
434 }
435 }