19
19
import java .lang .annotation .Annotation ;
20
20
import java .lang .reflect .AnnotatedElement ;
21
21
import java .lang .reflect .Constructor ;
22
+ import java .lang .reflect .Executable ;
22
23
import java .lang .reflect .Member ;
23
24
import java .lang .reflect .Method ;
25
+ import java .lang .reflect .Parameter ;
24
26
import java .lang .reflect .ParameterizedType ;
25
27
import java .lang .reflect .Type ;
26
28
import java .util .HashMap ;
@@ -54,6 +56,8 @@ public class MethodParameter {
54
56
55
57
private final int parameterIndex ;
56
58
59
+ private volatile Parameter parameter ;
60
+
57
61
private int nestingLevel = 1 ;
58
62
59
63
/** Map from Integer level to Integer type index */
@@ -98,7 +102,7 @@ public MethodParameter(Method method, int parameterIndex) {
98
102
public MethodParameter (Method method , int parameterIndex , int nestingLevel ) {
99
103
Assert .notNull (method , "Method must not be null" );
100
104
this .method = method ;
101
- this .parameterIndex = parameterIndex ;
105
+ this .parameterIndex = validateIndex ( method , parameterIndex ) ;
102
106
this .nestingLevel = nestingLevel ;
103
107
this .constructor = null ;
104
108
}
@@ -123,7 +127,7 @@ public MethodParameter(Constructor<?> constructor, int parameterIndex) {
123
127
public MethodParameter (Constructor <?> constructor , int parameterIndex , int nestingLevel ) {
124
128
Assert .notNull (constructor , "Constructor must not be null" );
125
129
this .constructor = constructor ;
126
- this .parameterIndex = parameterIndex ;
130
+ this .parameterIndex = validateIndex ( constructor , parameterIndex ) ;
127
131
this .nestingLevel = nestingLevel ;
128
132
this .method = null ;
129
133
}
@@ -138,6 +142,7 @@ public MethodParameter(MethodParameter original) {
138
142
this .method = original .method ;
139
143
this .constructor = original .constructor ;
140
144
this .parameterIndex = original .parameterIndex ;
145
+ this .parameter = original .parameter ;
141
146
this .nestingLevel = original .nestingLevel ;
142
147
this .typeIndexesPerLevel = original .typeIndexesPerLevel ;
143
148
this .containingClass = original .containingClass ;
@@ -179,15 +184,7 @@ public Class<?> getDeclaringClass() {
179
184
* @return the Method or Constructor as Member
180
185
*/
181
186
public Member getMember () {
182
- // NOTE: no ternary expression to retain JDK <8 compatibility even when using
183
- // the JDK 8 compiler (potentially selecting java.lang.reflect.Executable
184
- // as common type, with that new base class not available on older JDKs)
185
- if (this .method != null ) {
186
- return this .method ;
187
- }
188
- else {
189
- return this .constructor ;
190
- }
187
+ return getExecutable ();
191
188
}
192
189
193
190
/**
@@ -197,15 +194,27 @@ public Member getMember() {
197
194
* @return the Method or Constructor as AnnotatedElement
198
195
*/
199
196
public AnnotatedElement getAnnotatedElement () {
200
- // NOTE: no ternary expression to retain JDK <8 compatibility even when using
201
- // the JDK 8 compiler (potentially selecting java.lang.reflect.Executable
202
- // as common type, with that new base class not available on older JDKs)
203
- if (this .method != null ) {
204
- return this .method ;
205
- }
206
- else {
207
- return this .constructor ;
197
+ return getExecutable ();
198
+ }
199
+
200
+ /**
201
+ * Return the wrapped executable.
202
+ * @return the Method or Constructor as Executable
203
+ * @since 5.0
204
+ */
205
+ public Executable getExecutable () {
206
+ return (this .method != null ? this .method : this .constructor );
207
+ }
208
+
209
+ /**
210
+ * Return the {@link Parameter} descriptor for method/constructor parameter.
211
+ * @since 5.0
212
+ */
213
+ public Parameter getParameter () {
214
+ if (this .parameter == null ) {
215
+ this .parameter = getExecutable ().getParameters ()[this .parameterIndex ];
208
216
}
217
+ return this .parameter ;
209
218
}
210
219
211
220
/**
@@ -570,11 +579,11 @@ public boolean equals(Object other) {
570
579
if (this == other ) {
571
580
return true ;
572
581
}
573
- if (!( other instanceof MethodParameter )) {
582
+ if (other == null || getClass () != other . getClass ( )) {
574
583
return false ;
575
584
}
576
585
MethodParameter otherParam = (MethodParameter ) other ;
577
- return (this .parameterIndex == otherParam .parameterIndex && getMember ().equals (otherParam .getMember ()));
586
+ return (this .parameterIndex == otherParam .parameterIndex && getExecutable ().equals (otherParam .getExecutable ()));
578
587
}
579
588
580
589
@ Override
@@ -596,23 +605,73 @@ public MethodParameter clone() {
596
605
597
606
/**
598
607
* Create a new MethodParameter for the given method or constructor.
599
- * <p>This is a convenience constructor for scenarios where a
608
+ * <p>This is a convenience factory method for scenarios where a
600
609
* Method or Constructor reference is treated in a generic fashion.
601
610
* @param methodOrConstructor the Method or Constructor to specify a parameter for
602
611
* @param parameterIndex the index of the parameter
603
612
* @return the corresponding MethodParameter instance
613
+ * @deprecated as of 5.0, in favor of {@link #forExecutable}
604
614
*/
615
+ @ Deprecated
605
616
public static MethodParameter forMethodOrConstructor (Object methodOrConstructor , int parameterIndex ) {
606
- if (methodOrConstructor instanceof Method ) {
607
- return new MethodParameter ((Method ) methodOrConstructor , parameterIndex );
617
+ if (!(methodOrConstructor instanceof Executable )) {
618
+ throw new IllegalArgumentException (
619
+ "Given object [" + methodOrConstructor + "] is neither a Method nor a Constructor" );
608
620
}
609
- else if (methodOrConstructor instanceof Constructor ) {
610
- return new MethodParameter ((Constructor <?>) methodOrConstructor , parameterIndex );
621
+ return forExecutable ((Executable ) methodOrConstructor , parameterIndex );
622
+ }
623
+
624
+ /**
625
+ * Create a new MethodParameter for the given method or constructor.
626
+ * <p>This is a convenience factory method for scenarios where a
627
+ * Method or Constructor reference is treated in a generic fashion.
628
+ * @param executable the Method or Constructor to specify a parameter for
629
+ * @param parameterIndex the index of the parameter
630
+ * @return the corresponding MethodParameter instance
631
+ * @since 5.0
632
+ */
633
+ public static MethodParameter forExecutable (Executable executable , int parameterIndex ) {
634
+ if (executable instanceof Method ) {
635
+ return new MethodParameter ((Method ) executable , parameterIndex );
636
+ }
637
+ else if (executable instanceof Constructor ) {
638
+ return new MethodParameter ((Constructor <?>) executable , parameterIndex );
611
639
}
612
640
else {
613
- throw new IllegalArgumentException (
614
- "Given object [" + methodOrConstructor + "] is neither a Method nor a Constructor" );
641
+ throw new IllegalArgumentException ("Not a Method/Constructor: " + executable );
642
+ }
643
+ }
644
+
645
+ /**
646
+ * Create a new MethodParameter for the given parameter descriptor.
647
+ * <p>This is a convenience factory method for scenarios where a
648
+ * Java 8 {@link Parameter} descriptor is already available.
649
+ * @param parameter the parameter descriptor
650
+ * @return the corresponding MethodParameter instance
651
+ * @since 5.0
652
+ */
653
+ public static MethodParameter forParameter (Parameter parameter ) {
654
+ return forExecutable (parameter .getDeclaringExecutable (), findParameterIndex (parameter ));
655
+ }
656
+
657
+ protected static int findParameterIndex (Parameter parameter ) {
658
+ Executable executable = parameter .getDeclaringExecutable ();
659
+ Parameter [] allParams = executable .getParameters ();
660
+ for (int i = 0 ; i < allParams .length ; i ++) {
661
+ if (parameter == allParams [i ]) {
662
+ return i ;
663
+ }
664
+ }
665
+ throw new IllegalArgumentException ("Given parameter [" + parameter +
666
+ "] does not match any parameter in the declaring executable" );
667
+ }
668
+
669
+ private static int validateIndex (Executable executable , int parameterIndex ) {
670
+ int count = executable .getParameterCount ();
671
+ if (parameterIndex >= count ) {
672
+ throw new IllegalArgumentException ("Parameter index needs to be between 0 and " + (count - 1 ));
615
673
}
674
+ return parameterIndex ;
616
675
}
617
676
618
677
}
0 commit comments