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