55
55
* @author Andy Clement
56
56
* @author Sam Brannen
57
57
* @author Sebastien Deleuze
58
+ * @author Phillip Webb
58
59
* @since 2.0
59
60
* @see org.springframework.core.annotation.SynthesizingMethodParameter
60
61
*/
@@ -76,6 +77,7 @@ public class MethodParameter {
76
77
@ Nullable
77
78
Map <Integer , Integer > typeIndexesPerLevel ;
78
79
80
+ /** The containing class. Could also be supplied by overriding {@link #getContainingClass()} */
79
81
@ Nullable
80
82
private volatile Class <?> containingClass ;
81
83
@@ -150,6 +152,24 @@ public MethodParameter(Constructor<?> constructor, int parameterIndex, int nesti
150
152
this .nestingLevel = nestingLevel ;
151
153
}
152
154
155
+ /**
156
+ * Internal constructor used to create a {@link MethodParameter} with a
157
+ * containing class already set.
158
+ * @param executable the Executable to specify a parameter for
159
+ * @param parameterIndex the index of the parameter
160
+ * @param containingClass the containing class
161
+ * @since 5.2
162
+ */
163
+ MethodParameter (Executable executable , int parameterIndex ,
164
+ @ Nullable Class <?> containingClass ) {
165
+
166
+ Assert .notNull (executable , "Executable must not be null" );
167
+ this .executable = executable ;
168
+ this .parameterIndex = validateIndex (executable , parameterIndex );
169
+ this .nestingLevel = 1 ;
170
+ this .containingClass = containingClass ;
171
+ }
172
+
153
173
/**
154
174
* Copy constructor, resulting in an independent MethodParameter object
155
175
* based on the same metadata and cache state that the original object was in.
@@ -252,15 +272,20 @@ public int getParameterIndex() {
252
272
/**
253
273
* Increase this parameter's nesting level.
254
274
* @see #getNestingLevel()
275
+ * @deprecated since 5.2 in favor of {@link #nested(Integer)}
255
276
*/
277
+ @ Deprecated
256
278
public void increaseNestingLevel () {
257
279
this .nestingLevel ++;
258
280
}
259
281
260
282
/**
261
283
* Decrease this parameter's nesting level.
262
284
* @see #getNestingLevel()
285
+ * @deprecated since 5.2 in favor of retaining the original MethodParameter and
286
+ * using {@link #nested(Integer)} if nesting is required
263
287
*/
288
+ @ Deprecated
264
289
public void decreaseNestingLevel () {
265
290
getTypeIndexesPerLevel ().remove (this .nestingLevel );
266
291
this .nestingLevel --;
@@ -280,11 +305,22 @@ public int getNestingLevel() {
280
305
* @param typeIndex the corresponding type index
281
306
* (or {@code null} for the default type index)
282
307
* @see #getNestingLevel()
308
+ * @deprecated since 5.2 in favor of {@link #withTypeIndex}
283
309
*/
310
+ @ Deprecated
284
311
public void setTypeIndexForCurrentLevel (int typeIndex ) {
285
312
getTypeIndexesPerLevel ().put (this .nestingLevel , typeIndex );
286
313
}
287
314
315
+ /**
316
+ * Return a variant of this {@code MethodParameter} with the type for the current
317
+ * level set to the specified value.
318
+ * @param typeIndex the new type index
319
+ */
320
+ public MethodParameter withTypeIndex (int typeIndex ) {
321
+ return nested (this .nestingLevel , typeIndex );
322
+ }
323
+
288
324
/**
289
325
* Return the type index for the current nesting level.
290
326
* @return the corresponding type index, or {@code null}
@@ -319,22 +355,45 @@ private Map<Integer, Integer> getTypeIndexesPerLevel() {
319
355
320
356
/**
321
357
* Return a variant of this {@code MethodParameter} which points to the
322
- * same parameter but one nesting level deeper. This is effectively the
323
- * same as {@link #increaseNestingLevel()}, just with an independent
324
- * {@code MethodParameter} object (e.g. in case of the original being cached).
358
+ * same parameter but one nesting level deeper.
325
359
* @since 4.3
326
360
*/
327
361
public MethodParameter nested () {
362
+ return nested (null );
363
+ }
364
+
365
+ /**
366
+ * Return a variant of this {@code MethodParameter} which points to the
367
+ * same parameter but one nesting level deeper.
368
+ * @param typeIndex the type index for the new nesting level
369
+ * @since 5.2
370
+ */
371
+ public MethodParameter nested (@ Nullable Integer typeIndex ) {
328
372
MethodParameter nestedParam = this .nestedMethodParameter ;
329
- if (nestedParam != null ) {
373
+ if (nestedParam != null && typeIndex == null ) {
330
374
return nestedParam ;
331
375
}
332
- nestedParam = clone ();
333
- nestedParam .nestingLevel = this .nestingLevel + 1 ;
334
- this .nestedMethodParameter = nestedParam ;
376
+ nestedParam = nested (this .nestingLevel + 1 , typeIndex );
377
+ if (typeIndex == null ) {
378
+ this .nestedMethodParameter = nestedParam ;
379
+ }
335
380
return nestedParam ;
336
381
}
337
382
383
+ private MethodParameter nested (int nestingLevel , @ Nullable Integer typeIndex ) {
384
+ MethodParameter copy = clone ();
385
+ copy .nestingLevel = nestingLevel ;
386
+ if (this .typeIndexesPerLevel != null ) {
387
+ copy .typeIndexesPerLevel = new HashMap <>(this .typeIndexesPerLevel );
388
+ }
389
+ if (typeIndex != null ) {
390
+ copy .getTypeIndexesPerLevel ().put (copy .nestingLevel , typeIndex );
391
+ }
392
+ copy .parameterType = null ;
393
+ copy .genericParameterType = null ;
394
+ return copy ;
395
+ }
396
+
338
397
/**
339
398
* Return whether this method indicates a parameter which is not required:
340
399
* either in the form of Java 8's {@link java.util.Optional}, any variant
@@ -376,21 +435,28 @@ public MethodParameter nestedIfOptional() {
376
435
return (getParameterType () == Optional .class ? nested () : this );
377
436
}
378
437
379
- /**
380
- * Set a containing class to resolve the parameter type against.
381
- */
438
+ public Class <?> getContainingClass () {
439
+ Class <?> containingClass = this .containingClass ;
440
+ return (containingClass != null ? containingClass : getDeclaringClass ());
441
+ }
442
+
443
+ @ Deprecated
382
444
void setContainingClass (Class <?> containingClass ) {
383
445
this .containingClass = containingClass ;
446
+ this .parameterType = null ;
384
447
}
385
448
386
- public Class <?> getContainingClass () {
387
- Class <?> containingClass = this .containingClass ;
388
- return (containingClass != null ? containingClass : getDeclaringClass ());
449
+ public MethodParameter withContainingClass (@ Nullable Class <?> containingClass ) {
450
+ MethodParameter result = clone ();
451
+ result .containingClass = containingClass ;
452
+ result .parameterType = null ;
453
+ return result ;
389
454
}
390
455
391
456
/**
392
457
* Set a resolved (generic) parameter type.
393
458
*/
459
+ @ Deprecated
394
460
void setParameterType (@ Nullable Class <?> parameterType ) {
395
461
this .parameterType = parameterType ;
396
462
}
@@ -401,18 +467,16 @@ void setParameterType(@Nullable Class<?> parameterType) {
401
467
*/
402
468
public Class <?> getParameterType () {
403
469
Class <?> paramType = this .parameterType ;
470
+ if (paramType != null ) {
471
+ return paramType ;
472
+ }
473
+ if (getContainingClass () != null ) {
474
+ paramType = ResolvableType .forMethodParameter (this , null , 1 , null ).resolve ();
475
+ }
404
476
if (paramType == null ) {
405
- if (this .parameterIndex < 0 ) {
406
- Method method = getMethod ();
407
- paramType = (method != null ?
408
- (KotlinDetector .isKotlinReflectPresent () && KotlinDetector .isKotlinType (getContainingClass ()) ?
409
- KotlinDelegate .getReturnType (method ) : method .getReturnType ()) : void .class );
410
- }
411
- else {
412
- paramType = this .executable .getParameterTypes ()[this .parameterIndex ];
413
- }
414
- this .parameterType = paramType ;
477
+ paramType = computeParameterType ();
415
478
}
479
+ this .parameterType = paramType ;
416
480
return paramType ;
417
481
}
418
482
@@ -442,13 +506,27 @@ public Type getGenericParameterType() {
442
506
index = this .parameterIndex - 1 ;
443
507
}
444
508
paramType = (index >= 0 && index < genericParameterTypes .length ?
445
- genericParameterTypes [index ] : getParameterType ());
509
+ genericParameterTypes [index ] : computeParameterType ());
446
510
}
447
511
this .genericParameterType = paramType ;
448
512
}
449
513
return paramType ;
450
514
}
451
515
516
+ private Class <?> computeParameterType () {
517
+ if (this .parameterIndex < 0 ) {
518
+ Method method = getMethod ();
519
+ if (method == null ) {
520
+ return void .class ;
521
+ }
522
+ if (KotlinDetector .isKotlinReflectPresent () && KotlinDetector .isKotlinType (getContainingClass ())) {
523
+ return KotlinDelegate .getReturnType (method );
524
+ }
525
+ return method .getReturnType ();
526
+ }
527
+ return this .executable .getParameterTypes ()[this .parameterIndex ];
528
+ }
529
+
452
530
/**
453
531
* Return the nested type of the method/constructor parameter.
454
532
* @return the parameter type (never {@code null})
@@ -688,7 +766,6 @@ public MethodParameter clone() {
688
766
return new MethodParameter (this );
689
767
}
690
768
691
-
692
769
/**
693
770
* Create a new MethodParameter for the given method or constructor.
694
771
* <p>This is a convenience factory method for scenarios where a
0 commit comments