1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.core;
18
19 import java.lang.annotation.Annotation;
20 import java.lang.reflect.AnnotatedElement;
21 import java.lang.reflect.Constructor;
22 import java.lang.reflect.Member;
23 import java.lang.reflect.Method;
24 import java.lang.reflect.ParameterizedType;
25 import java.lang.reflect.Type;
26 import java.util.HashMap;
27 import java.util.Map;
28
29 import org.springframework.util.Assert;
30
31
32
33
34
35
36
37
38
39
40
41
42 public class MethodParameter {
43
44 private final Method method;
45
46 private final Constructor<?> constructor;
47
48 private final int parameterIndex;
49
50 private int nestingLevel = 1;
51
52
53 Map<Integer, Integer> typeIndexesPerLevel;
54
55 private volatile Class<?> containingClass;
56
57 private volatile Class<?> parameterType;
58
59 private volatile Type genericParameterType;
60
61 private volatile Annotation[] parameterAnnotations;
62
63 private volatile ParameterNameDiscoverer parameterNameDiscoverer;
64
65 private volatile String parameterName;
66
67
68
69
70
71
72
73 public MethodParameter(Method method, int parameterIndex) {
74 this(method, parameterIndex, 1);
75 }
76
77
78
79
80
81
82
83
84
85
86
87 public MethodParameter(Method method, int parameterIndex, int nestingLevel) {
88 Assert.notNull(method, "Method must not be null");
89 this.method = method;
90 this.parameterIndex = parameterIndex;
91 this.nestingLevel = nestingLevel;
92 this.constructor = null;
93 }
94
95
96
97
98
99
100 public MethodParameter(Constructor<?> constructor, int parameterIndex) {
101 this(constructor, parameterIndex, 1);
102 }
103
104
105
106
107
108
109
110
111
112 public MethodParameter(Constructor<?> constructor, int parameterIndex, int nestingLevel) {
113 Assert.notNull(constructor, "Constructor must not be null");
114 this.constructor = constructor;
115 this.parameterIndex = parameterIndex;
116 this.nestingLevel = nestingLevel;
117 this.method = null;
118 }
119
120
121
122
123
124
125 public MethodParameter(MethodParameter original) {
126 Assert.notNull(original, "Original must not be null");
127 this.method = original.method;
128 this.constructor = original.constructor;
129 this.parameterIndex = original.parameterIndex;
130 this.nestingLevel = original.nestingLevel;
131 this.typeIndexesPerLevel = original.typeIndexesPerLevel;
132 this.containingClass = original.containingClass;
133 this.parameterType = original.parameterType;
134 this.genericParameterType = original.genericParameterType;
135 this.parameterAnnotations = original.parameterAnnotations;
136 this.parameterNameDiscoverer = original.parameterNameDiscoverer;
137 this.parameterName = original.parameterName;
138 }
139
140
141
142
143
144
145
146 public Method getMethod() {
147 return this.method;
148 }
149
150
151
152
153
154
155 public Constructor<?> getConstructor() {
156 return this.constructor;
157 }
158
159
160
161
162
163 public Member getMember() {
164
165
166
167 if (this.method != null) {
168 return this.method;
169 }
170 else {
171 return this.constructor;
172 }
173 }
174
175
176
177
178
179 public AnnotatedElement getAnnotatedElement() {
180
181
182
183 if (this.method != null) {
184 return this.method;
185 }
186 else {
187 return this.constructor;
188 }
189 }
190
191
192
193
194 public Class<?> getDeclaringClass() {
195 return getMember().getDeclaringClass();
196 }
197
198
199
200
201
202 public int getParameterIndex() {
203 return this.parameterIndex;
204 }
205
206
207
208
209
210 public void increaseNestingLevel() {
211 this.nestingLevel++;
212 }
213
214
215
216
217
218 public void decreaseNestingLevel() {
219 getTypeIndexesPerLevel().remove(this.nestingLevel);
220 this.nestingLevel--;
221 }
222
223
224
225
226
227
228 public int getNestingLevel() {
229 return this.nestingLevel;
230 }
231
232
233
234
235
236
237
238 public void setTypeIndexForCurrentLevel(int typeIndex) {
239 getTypeIndexesPerLevel().put(this.nestingLevel, typeIndex);
240 }
241
242
243
244
245
246
247
248 public Integer getTypeIndexForCurrentLevel() {
249 return getTypeIndexForLevel(this.nestingLevel);
250 }
251
252
253
254
255
256
257
258 public Integer getTypeIndexForLevel(int nestingLevel) {
259 return getTypeIndexesPerLevel().get(nestingLevel);
260 }
261
262
263
264
265 private Map<Integer, Integer> getTypeIndexesPerLevel() {
266 if (this.typeIndexesPerLevel == null) {
267 this.typeIndexesPerLevel = new HashMap<Integer, Integer>(4);
268 }
269 return this.typeIndexesPerLevel;
270 }
271
272
273
274
275
276 void setContainingClass(Class<?> containingClass) {
277 this.containingClass = containingClass;
278 }
279
280 public Class<?> getContainingClass() {
281 return (this.containingClass != null ? this.containingClass : getDeclaringClass());
282 }
283
284
285
286
287 void setParameterType(Class<?> parameterType) {
288 this.parameterType = parameterType;
289 }
290
291
292
293
294
295 public Class<?> getParameterType() {
296 if (this.parameterType == null) {
297 if (this.parameterIndex < 0) {
298 this.parameterType = (this.method != null ? this.method.getReturnType() : null);
299 }
300 else {
301 this.parameterType = (this.method != null ?
302 this.method.getParameterTypes()[this.parameterIndex] :
303 this.constructor.getParameterTypes()[this.parameterIndex]);
304 }
305 }
306 return this.parameterType;
307 }
308
309
310
311
312
313
314 public Type getGenericParameterType() {
315 if (this.genericParameterType == null) {
316 if (this.parameterIndex < 0) {
317 this.genericParameterType = (this.method != null ? this.method.getGenericReturnType() : null);
318 }
319 else {
320 this.genericParameterType = (this.method != null ?
321 this.method.getGenericParameterTypes()[this.parameterIndex] :
322 this.constructor.getGenericParameterTypes()[this.parameterIndex]);
323 }
324 }
325 return this.genericParameterType;
326 }
327
328
329
330
331
332
333
334 public Class<?> getNestedParameterType() {
335 if (this.nestingLevel > 1) {
336 Type type = getGenericParameterType();
337 for (int i = 2; i <= this.nestingLevel; i++) {
338 if (type instanceof ParameterizedType) {
339 Type[] args = ((ParameterizedType) type).getActualTypeArguments();
340 Integer index = getTypeIndexForLevel(i);
341 type = args[index != null ? index : args.length - 1];
342 }
343 }
344 if (type instanceof Class) {
345 return (Class<?>) type;
346 }
347 else if (type instanceof ParameterizedType) {
348 Type arg = ((ParameterizedType) type).getRawType();
349 if (arg instanceof Class) {
350 return (Class<?>) arg;
351 }
352 }
353 return Object.class;
354 }
355 else {
356 return getParameterType();
357 }
358 }
359
360
361
362
363 public Annotation[] getMethodAnnotations() {
364 return getAnnotatedElement().getAnnotations();
365 }
366
367
368
369
370
371
372 public <T extends Annotation> T getMethodAnnotation(Class<T> annotationType) {
373 return getAnnotatedElement().getAnnotation(annotationType);
374 }
375
376
377
378
379 public Annotation[] getParameterAnnotations() {
380 if (this.parameterAnnotations == null) {
381 Annotation[][] annotationArray = (this.method != null ?
382 this.method.getParameterAnnotations() : this.constructor.getParameterAnnotations());
383 if (this.parameterIndex >= 0 && this.parameterIndex < annotationArray.length) {
384 this.parameterAnnotations = annotationArray[this.parameterIndex];
385 }
386 else {
387 this.parameterAnnotations = new Annotation[0];
388 }
389 }
390 return this.parameterAnnotations;
391 }
392
393
394
395
396
397
398 @SuppressWarnings("unchecked")
399 public <T extends Annotation> T getParameterAnnotation(Class<T> annotationType) {
400 Annotation[] anns = getParameterAnnotations();
401 for (Annotation ann : anns) {
402 if (annotationType.isInstance(ann)) {
403 return (T) ann;
404 }
405 }
406 return null;
407 }
408
409
410
411
412 public boolean hasParameterAnnotations() {
413 return (getParameterAnnotations().length != 0);
414 }
415
416
417
418
419 public <T extends Annotation> boolean hasParameterAnnotation(Class<T> annotationType) {
420 return (getParameterAnnotation(annotationType) != null);
421 }
422
423
424
425
426
427
428
429 public void initParameterNameDiscovery(ParameterNameDiscoverer parameterNameDiscoverer) {
430 this.parameterNameDiscoverer = parameterNameDiscoverer;
431 }
432
433
434
435
436
437
438
439
440 public String getParameterName() {
441 ParameterNameDiscoverer discoverer = this.parameterNameDiscoverer;
442 if (discoverer != null) {
443 String[] parameterNames = (this.method != null ?
444 discoverer.getParameterNames(this.method) : discoverer.getParameterNames(this.constructor));
445 if (parameterNames != null) {
446 this.parameterName = parameterNames[this.parameterIndex];
447 }
448 this.parameterNameDiscoverer = null;
449 }
450 return this.parameterName;
451 }
452
453
454 @Override
455 public boolean equals(Object other) {
456 if (this == other) {
457 return true;
458 }
459 if (!(other instanceof MethodParameter)) {
460 return false;
461 }
462 MethodParameter otherParam = (MethodParameter) other;
463 return (this.parameterIndex == otherParam.parameterIndex && getMember().equals(otherParam.getMember()));
464 }
465
466 @Override
467 public int hashCode() {
468 return (getMember().hashCode() * 31 + this.parameterIndex);
469 }
470
471
472
473
474
475
476
477
478
479
480 public static MethodParameter forMethodOrConstructor(Object methodOrConstructor, int parameterIndex) {
481 if (methodOrConstructor instanceof Method) {
482 return new MethodParameter((Method) methodOrConstructor, parameterIndex);
483 }
484 else if (methodOrConstructor instanceof Constructor) {
485 return new MethodParameter((Constructor<?>) methodOrConstructor, parameterIndex);
486 }
487 else {
488 throw new IllegalArgumentException(
489 "Given object [" + methodOrConstructor + "] is neither a Method nor a Constructor");
490 }
491 }
492
493 }