001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.juneau.commons.reflect;
018
019import static org.apache.juneau.commons.function.Suppliers.*;
020import static org.apache.juneau.commons.reflect.ClassArrayFormat.*;
021import static org.apache.juneau.commons.reflect.ClassNameFormat.*;
022import static org.apache.juneau.commons.utils.CollectionUtils.*;
023import static org.apache.juneau.commons.utils.Shorts.*;
024
025import java.lang.annotation.*;
026import java.lang.reflect.*;
027import java.util.*;
028import java.util.function.*;
029import java.util.stream.*;
030
031import org.apache.juneau.commons.function.*;
032import org.apache.juneau.commons.inject.*;
033import org.apache.juneau.commons.settings.*;
034import org.apache.juneau.commons.utils.*;
035
036/**
037 * Lightweight utility class for introspecting information about a method or constructor parameter.
038 *
039 * <p>
040 * This class provides a convenient wrapper around {@link Parameter} that extends the standard Java reflection
041 * API with additional functionality for parameter introspection, annotation handling, and name resolution.
042 * It supports resolving parameter names from bytecode (when compiled with <c>-parameters</c>) or from
043 * <ja>@Name</ja> annotations.
044 *
045 * <h5 class='section'>Features:</h5>
046 * <ul class='spaced-list'>
047 *    <li>Parameter introspection - access parameter metadata, type, annotations
048 *    <li>Name resolution - resolve parameter names from bytecode or annotations
049 *    <li>Qualifier support - extract qualifier names from annotations
050 *    <li>Hierarchy traversal - find matching parameters in parent methods/constructors
051 *    <li>Annotation support - get annotations declared on the parameter
052 * </ul>
053 *
054 * <h5 class='section'>Use Cases:</h5>
055 * <ul class='spaced-list'>
056 *    <li>Introspecting parameter metadata for code generation or analysis
057 *    <li>Resolving parameter names for dependency injection frameworks
058 *    <li>Finding annotations on parameters
059 *    <li>Working with parameter types and qualifiers
060 *    <li>Building frameworks that need to analyze method/constructor signatures
061 * </ul>
062 *
063 * <h5 class='section'>Usage:</h5>
064 * <p class='bjava'>
065 *    <jc>// Get ParameterInfo from a method</jc>
066 *    MethodInfo <jv>mi</jv> = ...;
067 *    ParameterInfo <jv>param</jv> = <jv>mi</jv>.getParameters().get(0);
068 *
069 *    <jc>// Get parameter type</jc>
070 *    ClassInfo <jv>type</jv> = <jv>param</jv>.getParameterType();
071 *
072 *    <jc>// Get resolved name (from bytecode or @Name annotation)</jc>
073 *    String <jv>name</jv> = <jv>param</jv>.getResolvedName();
074 *
075 *    <jc>// Get annotations</jc>
076 *    List&lt;AnnotationInfo&lt;MyAnnotation&gt;&gt; <jv>annotations</jv> =
077 *       <jv>param</jv>.getAnnotations(MyAnnotation.<jk>class</jk>).toList();
078 * </p>
079 *
080 * <h5 class='section'>Parameter Name Resolution:</h5>
081 * <p>
082 * Parameter names are resolved in the following order:
083 * <ol class='spaced-list'>
084 *    <li><ja>@Name</ja> annotation value (if present)
085 *    <li>Bytecode parameter names (if compiled with <c>-parameters</c> flag)
086 *    <li><c>arg0</c>, <c>arg1</c>, etc. (fallback if names unavailable)
087 * </ol>
088 *
089 * <h5 class='section'>See Also:</h5><ul>
090 *    <li class='jc'>{@link MethodInfo} - Method introspection
091 *    <li class='jc'>{@link ConstructorInfo} - Constructor introspection
092 *    <li class='jc'>{@link ExecutableInfo} - Common executable functionality
093 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauCommonsReflection">Reflection Package</a>
094 * </ul>
095 */
096@SuppressWarnings({
097   "java:S1192", // Duplicated literals (argument/property names) read more clearly inline than as constants
098   "unchecked" // Casts to AnnotationInfo<A> in the annotation stream and to Supplier<Object>/Class<Object>/Provider<Object> in the JSR-330 Provider bean resolution are guarded by the requested type
099})
100public final class ParameterInfo extends ElementInfo implements Annotatable {
101
102   /**
103    * Resettable supplier for the system property to disable bytecode parameter name detection.
104    *
105    * <p>
106    * When the value is <jk>true</jk>, parameter names will only come from <ja>@Name</ja>
107    * annotations and not from bytecode parameter names (even if compiled with <c>-parameters</c> flag).
108    *
109    * <p>
110    * This can be set via system property: <c>juneau.disableParamNameDetection=true</c>
111    *
112    * <p>
113    * The supplier can be reset for testing purposes using {@link #resetDisableParamNameDetection()}.
114    */
115   static final Memoizer<Boolean> DISABLE_PARAM_NAME_DETECTION = memoizer(() -> Settings.get().get("juneau.disableParamNameDetection").asBoolean().orElse(false));
116
117   /**
118    * Creates a ParameterInfo wrapper for the specified parameter.
119    *
120    * <p>
121    * This convenience method automatically determines the declaring executable from the parameter
122    * and finds the matching ParameterInfo.
123    *
124    * <h5 class='section'>Example:</h5>
125    * <p class='bjava'>
126    *    Parameter <jv>p</jv> = ...;
127    *    ParameterInfo <jv>pi</jv> = ParameterInfo.<jsm>of</jsm>(<jv>p</jv>);
128    * </p>
129    *
130    * @param inner The parameter being wrapped. Must not be <jk>null</jk>.
131    * @return A ParameterInfo object wrapping the parameter.
132    * @throws IllegalArgumentException If the parameter is <jk>null</jk> or cannot be found in its declaring executable.
133    */
134   public static ParameterInfo of(Parameter inner) {
135      reqnn("inner", inner);
136      var exec = inner.getDeclaringExecutable();
137      ExecutableInfo execInfo;
138      if (exec instanceof Constructor<?> exec2)
139         execInfo = ConstructorInfo.of(exec2);
140      else
141         execInfo = MethodInfo.of((Method)exec);
142      return execInfo.getParameters().stream()
143         .filter(x -> eq(x.inner(), inner))
144         .findFirst()
145         .orElse(null);
146   }
147
148   static void reset() {
149      DISABLE_PARAM_NAME_DETECTION.reset();
150   }
151
152   private final ExecutableInfo executable;
153   private final Parameter inner;
154
155   private final int index;
156   private final ClassInfo type;
157   private final Supplier<List<AnnotationInfo<Annotation>>> annotations;  // All annotations declared directly on this parameter.
158   private final Supplier<List<ParameterInfo>> matchingParameters;  // Matching parameters in parent methods.
159
160   private final Memoizer<String> resolvedName = memoizer(this::findNameInternal);  // Resolved name from @Name annotation or bytecode.
161
162   private final Memoizer<String> resolvedQualifier = memoizer(this::findQualifierInternal);  // Resolved qualifier from @Named or @Qualifier annotation.
163
164   private final Supplier<String> toString;  // String representation with modifiers, type, name, and varargs flag.
165
166   /**
167    * Constructor.
168    *
169    * <p>
170    * Creates a new ParameterInfo wrapper for the specified parameter. This constructor is protected
171    * and should not be called directly. ParameterInfo instances are typically obtained from
172    * {@link ExecutableInfo#getParameters()} or {@link #of(Parameter)}.
173    *
174    * @param executable The ExecutableInfo (MethodInfo or ConstructorInfo) that contains this parameter. Must not be <jk>null</jk>.
175    * @param inner The parameter being wrapped. Must not be <jk>null</jk>.
176    * @param index The zero-based index of this parameter in the method/constructor signature.
177    * @param type The ClassInfo representing the parameter type.
178    */
179   protected ParameterInfo(ExecutableInfo executable, Parameter inner, int index, ClassInfo type) {
180      super(inner.getModifiers());
181      this.executable = executable;
182      this.inner = inner;
183      this.index = index;
184      this.type = type;
185      this.annotations = memoize(() -> stream(inner.getAnnotations()).flatMap(AnnotationUtils::streamRepeated).map(a -> ai(this, a)).toList());
186      this.matchingParameters = memoize(this::findMatchingParameters);
187      this.toString = memoize(this::findToString);
188   }
189
190   /**
191    * Returns <jk>true</jk> if this parameter can accept the specified value.
192    *
193    * @param value The value to check.
194    * @return <jk>true</jk> if this parameter can accept the specified value.
195    */
196   public boolean canAccept(Object value) {
197      return getParameterType().canAcceptArg(value);
198   }
199
200   @Override /* Annotatable */
201   public AnnotatableType getAnnotatableType() { return AnnotatableType.PARAMETER_TYPE; }
202
203   /**
204    * Returns an {@link AnnotatedType} object that represents the use of a type to specify the type of this parameter.
205    *
206    * <p>
207    * Same as calling {@link Parameter#getAnnotatedType()}.
208    *
209    * <h5 class='section'>Example:</h5>
210    * <p class='bjava'>
211    *    <jc>// Get annotated type: void method(@NotNull String value)</jc>
212    *    ParameterInfo <jv>pi</jv> = ...;
213    *    AnnotatedType <jv>aType</jv> = <jv>pi</jv>.getAnnotatedType();
214    *    <jc>// Check for @NotNull on the type</jc>
215    * </p>
216    *
217    * @return An {@link AnnotatedType} object representing the type of this parameter.
218    * @see Parameter#getAnnotatedType()
219    */
220   public AnnotatedType getAnnotatedType() { return inner.getAnnotatedType(); }
221
222   /**
223    * Returns all annotations declared on this parameter.
224    *
225    * <p>
226    * Returns annotations directly declared on this parameter, wrapped as {@link AnnotationInfo} objects.
227    *
228    * <p>
229    * <b>Note on Repeatable Annotations:</b>
230    * Repeatable annotations (those marked with {@link Repeatable @Repeatable}) are automatically
231    * expanded into their individual annotation instances. For example, if a parameter has multiple {@code @Marshalled} annotations,
232    * this method returns each {@code @Marshalled} annotation separately, rather than the container annotation.
233    *
234    * @return
235    *    An unmodifiable list of annotations on this parameter, never <jk>null</jk>.
236    *    <br>Repeatable annotations are expanded into individual instances.
237    */
238   public List<AnnotationInfo<Annotation>> getAnnotations() { return annotations.get(); }
239
240   /**
241    * Returns a stream of annotation infos of the specified type declared on this parameter.
242    *
243    * @param <A> The annotation type.
244    * @param type The annotation type.
245    * @return A stream of annotation infos, never <jk>null</jk>.
246    */
247   public <A extends Annotation> Stream<AnnotationInfo<A>> getAnnotations(Class<A> type) {
248      return getAnnotations().stream().filter(x -> x.isType(type)).map(x -> (AnnotationInfo<A>)x);
249   }
250
251   /**
252    * Returns the constructor that this parameter belongs to.
253    *
254    * @return The constructor that this parameter belongs to, or <jk>null</jk> if it belongs to a method.
255    */
256   public ConstructorInfo getConstructor() { return executable.isConstructor() ? (ConstructorInfo)executable : null; }
257
258   /**
259    * Returns the {@link ExecutableInfo} which declares this parameter.
260    *
261    * <p>
262    * Same as calling {@link Parameter#getDeclaringExecutable()} but returns {@link ExecutableInfo} instead.
263    *
264    * <h5 class='section'>Example:</h5>
265    * <p class='bjava'>
266    *    <jc>// Get the method or constructor that declares this parameter</jc>
267    *    ParameterInfo <jv>pi</jv> = ...;
268    *    ExecutableInfo <jv>executable</jv> = <jv>pi</jv>.getDeclaringExecutable();
269    *    <jk>if</jk> (<jv>executable</jv>.isConstructor()) {
270    *       ConstructorInfo <jv>ci</jv> = (ConstructorInfo)<jv>executable</jv>;
271    *    }
272    * </p>
273    *
274    * @return The {@link ExecutableInfo} declaring this parameter.
275    * @see Parameter#getDeclaringExecutable()
276    */
277   public ExecutableInfo getDeclaringExecutable() { return executable; }
278
279   /**
280    * Returns the index position of this parameter.
281    *
282    * @return The index position of this parameter.
283    */
284   public int getIndex() { return index; }
285
286   @Override /* Annotatable */
287   public String getLabel() {
288      var exec = getDeclaringExecutable();
289      var label = exec.getDeclaringClass().getNameSimple() + "." + exec.getNameShort();
290      return label + "[" + index + "]";
291   }
292
293   /**
294    * Returns this parameter and all matching parameters in parent classes.
295    *
296    * <p>
297    * For constructors, searches parent class constructors for parameters with matching name and type,
298    * regardless of parameter count or position. This allows finding annotated parameters that may be
299    * inherited by child classes even when constructor signatures differ.
300    *
301    * <p>
302    * For methods, searches matching methods (same signature) in parent classes/interfaces
303    * for parameters at the same index with matching name and type.
304    *
305    * <h5 class='section'>Examples:</h5>
306    * <p class='bjava'>
307    *    <jc>// Constructor with different parameter counts:</jc>
308    *    <jk>class</jk> A {
309    *       A(String <jv>foo</jv>, <jk>int</jk> <jv>bar</jv>) {}
310    *    }
311    *    <jk>class</jk> B <jk>extends</jk> A {
312    *       B(String <jv>foo</jv>) {}
313    *    }
314    *    <jc>// For B's foo parameter, returns: [B.foo, A.foo]</jc>
315    *    ParameterInfo <jv>pi</jv> = ...;
316    *    List&lt;ParameterInfo&gt; <jv>matching</jv> = <jv>pi</jv>.getMatchingParameters();
317    * </p>
318    *
319    * @return A list of matching parameters including this one, in child-to-parent order.
320    */
321   public List<ParameterInfo> getMatchingParameters() { return matchingParameters.get(); }
322
323   /**
324    * Returns the method that this parameter belongs to.
325    *
326    * @return The method that this parameter belongs to, or <jk>null</jk> if it belongs to a constructor.
327    */
328   public MethodInfo getMethod() { return executable.isConstructor() ? null : (MethodInfo)executable; }
329
330   /**
331    * Returns the Java language modifiers for the parameter represented by this object, as an integer.
332    *
333    * <p>
334    * The {@link Modifier} class should be used to decode the modifiers.
335    *
336    * <p>
337    * Same as calling {@link Parameter#getModifiers()}.
338    *
339    * <h5 class='section'>Example:</h5>
340    * <p class='bjava'>
341    *    <jc>// Check if parameter is final</jc>
342    *    ParameterInfo <jv>pi</jv> = ...;
343    *    <jk>int</jk> <jv>modifiers</jv> = <jv>pi</jv>.getModifiers();
344    *    <jk>boolean</jk> <jv>isFinal</jv> = Modifier.<jsm>isFinal</jsm>(<jv>modifiers</jv>);
345    * </p>
346    *
347    * @return The Java language modifiers for this parameter.
348    * @see Parameter#getModifiers()
349    * @see Modifier
350    */
351   @Override
352   public int getModifiers() { return inner.getModifiers(); }
353
354   /**
355    * Returns the name of the parameter.
356    *
357    * <p>
358    * Searches for the name in the following order:
359    * <ol>
360    *    <li>@Name annotation value (takes precedence over bytecode parameter names)
361    *    <li>Bytecode parameter name (if compiled with -parameters flag)
362    *    <li>Matching parameters in parent classes/interfaces (for methods)
363    *    <li>Synthetic name like "arg0", "arg1", etc. (fallback)
364    * </ol>
365    *
366    * <p>
367    * This method works with any annotation named "Name" (from any package) that has a <c>String value()</c> method.
368    *
369    * @return The name of the parameter, never <jk>null</jk>.
370    * @see Parameter#getName()
371    */
372   public String getName() {
373      var name = getResolvedName();
374      return name != null ? name : inner.getName();
375   }
376
377   /**
378    * Returns a {@link Type} object that identifies the parameterized type for this parameter.
379    *
380    * <p>
381    * Same as calling {@link Parameter#getParameterizedType()}.
382    *
383    * <h5 class='section'>Example:</h5>
384    * <p class='bjava'>
385    *    <jc>// Get generic type information for parameter: List&lt;String&gt; values</jc>
386    *    ParameterInfo <jv>pi</jv> = ...;
387    *    Type <jv>type</jv> = <jv>pi</jv>.getParameterizedType();
388    *    <jk>if</jk> (<jv>type</jv> <jk>instanceof</jk> ParameterizedType) {
389    *       ParameterizedType <jv>pType</jv> = (ParameterizedType)<jv>type</jv>;
390    *       <jc>// pType.getActualTypeArguments()[0] is String.class</jc>
391    *    }
392    * </p>
393    *
394    * @return A {@link Type} object identifying the parameterized type.
395    * @see Parameter#getParameterizedType()
396    */
397   public Type getParameterizedType() { return inner.getParameterizedType(); }
398
399   /**
400    * Returns the class type of this parameter.
401    *
402    * @return The class type of this parameter.
403    */
404   public ClassInfo getParameterType() { return type; }
405
406   /**
407    * Finds the name of this parameter for bean property mapping.
408    *
409    * <p>
410    * Searches for the parameter name in the following order:
411    * <ol>
412    *    <li><ja>@Name</ja> annotation value
413    *    <li>Bytecode parameter name (if available and not disabled via system property)
414    *    <li>Matching parameters in parent classes/interfaces
415    * </ol>
416    *
417    * <p>
418    * This method is used for mapping constructor parameters to bean properties.
419    *
420    * <p>
421    * <b>Note:</b> This is different from {@link #getResolvedQualifier()} which looks for <ja>@Named</ja>
422    * annotations for bean injection purposes.
423    *
424    * @return The parameter name if found, or <jk>null</jk> if not available.
425    * @see #getResolvedQualifier()
426    * @see #getName()
427    */
428   public String getResolvedName() { return resolvedName.get(); }
429
430   /**
431    * Finds the bean injection qualifier for this parameter.
432    *
433    * <p>
434    * Searches for the <ja>@Named</ja> or <ja>@Qualifier</ja>
435    * annotation value to determine which named bean should be injected.
436    *
437    * <p>
438    * This method is used by the {@link BeanStore} for bean injection.
439    *
440    * <p>
441    * <b>Note:</b> This is different from {@link #getResolvedName()} which looks for <ja>@Name</ja>
442    * annotations for bean property mapping.
443    *
444    * @return The bean qualifier name if {@code @Named} or {@code @Qualifier} annotation is found, or <jk>null</jk> if not annotated.
445    * @see #getResolvedName()
446    */
447   public String getResolvedQualifier() { return resolvedQualifier.get(); }
448
449   /**
450    * Returns <jk>true</jk> if the parameter has a name.
451    *
452    * <p>
453    * This returns <jk>true</jk> if the parameter has an annotation with the simple name "Name",
454    * or if the parameter's name is present in the class file.
455    *
456    * @return <jk>true</jk> if the parameter has a name.
457    */
458   public boolean hasName() {
459      return getResolvedName() != null;
460   }
461
462   /**
463    * Returns the wrapped {@link Parameter} object.
464    *
465    * @return The wrapped {@link Parameter} object.
466    */
467   public Parameter inner() {
468      return inner;
469   }
470
471   /**
472    * Compares this ParameterInfo with the specified object for equality.
473    *
474    * <p>
475    * Two ParameterInfo objects are considered equal if they wrap the same underlying {@link Parameter} object.
476    * This delegates to the underlying {@link Parameter#equals(Object)} method.
477    *
478    * <p>
479    * This method makes ParameterInfo suitable for use as keys in hash-based collections such as {@link HashMap}
480    * and {@link HashSet}.
481    *
482    * @param obj The object to compare with.
483    * @return <jk>true</jk> if the objects are equal, <jk>false</jk> otherwise.
484    */
485   @Override
486   public boolean equals(Object obj) {
487      return obj instanceof ParameterInfo obj2 && eq(this, obj2, (x, y) -> eq(x.inner, y.inner));
488   }
489
490   /**
491    * Returns a hash code value for this ParameterInfo.
492    *
493    * <p>
494    * This delegates to the underlying {@link Parameter#hashCode()} method.
495    *
496    * <p>
497    * This method makes ParameterInfo suitable for use as keys in hash-based collections such as {@link HashMap}
498    * and {@link HashSet}.
499    *
500    * @return A hash code value for this ParameterInfo.
501    */
502   @Override
503   public int hashCode() {
504      return inner.hashCode();
505   }
506
507   @Override
508   public boolean is(ElementFlag flag) {
509      return switch (flag) {
510         case SYNTHETIC -> isSynthetic();
511         case NOT_SYNTHETIC -> ! isSynthetic();  // HTT
512         case VARARGS -> isVarArgs();
513         case NOT_VARARGS -> ! isVarArgs();
514         default -> super.is(flag);
515      };
516   }
517
518   /**
519    * Returns <jk>true</jk> if this parameter is implicitly declared in source code.
520    *
521    * <p>
522    * Returns <jk>true</jk> if this parameter is neither explicitly nor implicitly declared in source code.
523    *
524    * <p>
525    * Same as calling {@link Parameter#isImplicit()}.
526    *
527    * <h5 class='section'>Example:</h5>
528    * <p class='bjava'>
529    *    <jc>// Filter out implicit parameters</jc>
530    *    ParameterInfo <jv>pi</jv> = ...;
531    *    <jk>if</jk> (! <jv>pi</jv>.isImplicit()) {
532    *       <jc>// Process explicit parameter</jc>
533    *    }
534    * </p>
535    *
536    * @return <jk>true</jk> if this parameter is implicitly declared.
537    * @see Parameter#isImplicit()
538    */
539   public boolean isImplicit() { return inner.isImplicit(); }
540
541   /**
542    * Returns <jk>true</jk> if the parameter has a name according to the <c>.class</c> file.
543    *
544    * <p>
545    * Same as calling {@link Parameter#isNamePresent()}.
546    *
547    * <p>
548    * <b>Note:</b> This method is different from {@link #hasName()} which also checks for the presence
549    * of a <c>@Name</c> annotation. This method only checks if the name is present in the bytecode.
550    *
551    * <h5 class='section'>Example:</h5>
552    * <p class='bjava'>
553    *    <jc>// Check if parameter name is in bytecode</jc>
554    *    ParameterInfo <jv>pi</jv> = ...;
555    *    <jk>if</jk> (<jv>pi</jv>.isNamePresent()) {
556    *       String <jv>name</jv> = <jv>pi</jv>.getName();
557    *    }
558    * </p>
559    *
560    * @return <jk>true</jk> if the parameter has a name in the bytecode.
561    * @see Parameter#isNamePresent()
562    * @see #hasName()
563    */
564   public boolean isNamePresent() { return inner.isNamePresent(); }
565
566   /**
567    * Returns <jk>true</jk> if this parameter is a synthetic construct as defined by the Java Language Specification.
568    *
569    * <p>
570    * Same as calling {@link Parameter#isSynthetic()}.
571    *
572    * <h5 class='section'>Example:</h5>
573    * <p class='bjava'>
574    *    <jc>// Filter out compiler-generated parameters</jc>
575    *    ParameterInfo <jv>pi</jv> = ...;
576    *    <jk>if</jk> (! <jv>pi</jv>.isSynthetic()) {
577    *       <jc>// Process real parameter</jc>
578    *    }
579    * </p>
580    *
581    * @return <jk>true</jk> if this parameter is a synthetic construct.
582    * @see Parameter#isSynthetic()
583    */
584   public boolean isSynthetic() { return inner.isSynthetic(); }
585
586   /**
587    * Returns <jk>true</jk> if the parameter type is an exact match for the specified class.
588    *
589    * @param c The type to check.
590    * @return <jk>true</jk> if the parameter type is an exact match for the specified class.
591    */
592   public boolean isType(Class<?> c) {
593      return getParameterType().is(c);
594   }
595   //-----------------------------------------------------------------------------------------------------------------
596   // High Priority Methods (direct Parameter API compatibility)
597   //-----------------------------------------------------------------------------------------------------------------
598
599   /**
600    * Returns <jk>true</jk> if this parameter represents a variable argument list.
601    *
602    * <p>
603    * Same as calling {@link Parameter#isVarArgs()}.
604    *
605    * <p>
606    * Only returns <jk>true</jk> for the last parameter of a variable arity method.
607    *
608    * <h5 class='section'>Example:</h5>
609    * <p class='bjava'>
610    *    <jc>// Check if this is a varargs parameter</jc>
611    *    ParameterInfo <jv>pi</jv> = ...;
612    *    <jk>if</jk> (<jv>pi</jv>.isVarArgs()) {
613    *       <jc>// Handle variable arguments</jc>
614    *    }
615    * </p>
616    *
617    * @return <jk>true</jk> if this parameter represents a variable argument list.
618    * @see Parameter#isVarArgs()
619    */
620   public boolean isVarArgs() { return inner.isVarArgs(); }
621
622   /**
623    * Returns a detailed string representation of this parameter.
624    *
625    * <p>
626    * The returned string includes:
627    * <ul>
628    *    <li>Modifiers (final)
629    *    <li>Parameter type with generics (e.g., "List&lt;String&gt;")
630    *    <li>Parameter name (if available)
631    *    <li>Varargs indicator (if applicable)
632    * </ul>
633    *
634    * <h5 class='section'>Examples:</h5>
635    * <p class='bjava'>
636    *    <jc>// Simple parameter</jc>
637    *    ParameterInfo <jv>pi</jv> = ...;
638    *    <jv>pi</jv>.toString();
639    *    <jc>// Returns: "java.lang.String name"</jc>
640    *
641    *    <jc>// Final parameter</jc>
642    *    <jc>// Returns: "final java.lang.String name"</jc>
643    *
644    *    <jc>// Generic parameter</jc>
645    *    <jc>// Returns: "java.util.List&lt;java.lang.String&gt; items"</jc>
646    *
647    *    <jc>// Varargs parameter</jc>
648    *    <jc>// Returns: "java.lang.String... values"</jc>
649    *
650    *    <jc>// Parameter without name (fallback)</jc>
651    *    <jc>// Returns: "int arg0"</jc>
652    * </p>
653    *
654    * @return A detailed string representation including modifiers, type, name, and varargs flag.
655    */
656   @Override
657   public String toString() {
658      return toString.get();
659   }
660
661   private String findToString() {
662      var sb = new StringBuilder(128);
663
664      // Modifiers (final is common for parameters)
665      var mods = Modifier.toString(getModifiers());
666      if (nn(mods) && ! mods.isEmpty()) {
667         sb.append(mods).append(" ");
668      }
669
670      // Parameter type (use generic type if available to show generics)
671      var paramType = getParameterizedType();
672
673      // For varargs, we need to get the component type and display it with "..." instead of "[]"
674      if (isVarArgs()) {
675         // Get the component type of the array
676         var typeInfo = ClassInfo.of(paramType);
677         var componentType = typeInfo.getComponentType();
678         // Display the component type without array brackets, then add "..."
679         componentType.appendNameFormatted(sb, FULL, true, '$', BRACKETS);
680         sb.append("...");
681      } else {
682         ClassInfo.of(paramType).appendNameFormatted(sb, FULL, true, '$', BRACKETS);
683      }
684
685      // Parameter name (if available)
686      var name = getResolvedName();
687      if (nn(name)) {
688         sb.append(" ").append(name);
689      } else {
690         // Fallback to index-based name if no name available
691         sb.append(" arg").append(index);
692      }
693
694      return sb.toString();
695   }
696
697   private List<ParameterInfo> findMatchingParameters() {
698      if (executable instanceof ConstructorInfo executable2) {
699         // For constructors: search parent class constructors for parameters with matching index and type
700         // Note: We match by index and type only, not by name, to avoid circular dependency
701         // (getName() needs getMatchingParameters() which needs getName())
702         var list = new ArrayList<ParameterInfo>();
703
704         // Add this parameter first
705         list.add(this);
706
707         // Search parent classes for matching parameters
708         var cc = executable2.getDeclaringClass().getSuperclass();
709         while (nn(cc)) {
710            // Check all constructors in parent class
711            for (var pc : cc.getDeclaredConstructors()) {
712               // Check if constructor has parameter at this index with matching type
713               var params = pc.getParameters();
714               if (index < params.size() && getParameterType().is(params.get(index).getParameterType())) {
715                  list.add(params.get(index));
716               }
717            }
718            cc = cc.getSuperclass();
719         }
720
721         return list;
722      }
723      // For methods: use matching methods from parent classes
724      return ((MethodInfo)executable).getMatchingMethods().stream().map(m -> m.getParameter(index)).toList();
725   }
726
727   //-----------------------------------------------------------------------------------------------------------------
728   // Annotatable interface methods
729   //-----------------------------------------------------------------------------------------------------------------
730
731   private String findNameInternal() {
732      // Search through matching parameters in hierarchy for @Name annotations only.
733      // Note: We intentionally prioritize @Name annotations over bytecode parameter names
734      // because bytecode names are unreliable - users may or may not compile with -parameters flag.
735      for (var mp : getMatchingParameters()) {
736         for (var ai : mp.getAnnotations()) {
737            if (ai.hasNameSimple("Name")) {
738               var value = ai.getValue().orElse(null);
739               if (value != null)  // HTT
740                  return value;
741            }
742         }
743      }
744
745      return o(inner).filter(x -> x.isNamePresent()).filter(x -> ! DISABLE_PARAM_NAME_DETECTION.get()).map(x -> x.getName()).orElse(null);
746   }
747
748   private String findQualifierInternal() {
749      // Search through matching parameters in hierarchy for @Named or qualifier-meta annotations.
750      // @formatter:off
751      return getMatchingParameters().stream()
752         .flatMap(mp -> mp.getAnnotations().stream())
753         .map(JsrSupport::qualifierValue)
754         .filter(Objects::nonNull)
755         .findFirst()
756         .orElse(null);
757      // @formatter:on
758   }
759
760   /**
761    * Checks if this parameter can be resolved from the bean store.
762    *
763    * <p>
764    * The following parameter types are considered optional and always return <jk>true</jk>:
765    * <ul>
766    *    <li>Parameters of type <c>Optional&lt;T&gt;</c>
767    *    <li>Parameters of type <c>T[]</c>, <c>List&lt;T&gt;</c>, <c>Set&lt;T&gt;</c>, or <c>Map&lt;String,T&gt;</c>
768    * </ul>
769    *
770    * <p>
771    * If a parameter has a <ja>@Named</ja>or <ja>@Qualifier</ja> annotation,
772    * the method checks for a bean with that specific name in the bean store.  Otherwise, it checks for an unnamed bean
773    * of the parameter type in the bean store, and if not found, checks the <c>otherBeans</c> parameter.
774    *
775    * @param beanStore The bean store to check for beans.
776    * @param otherBeans Optional additional bean instances to check if not found in the bean store.
777    *    These are checked after the bean store but before returning <jk>false</jk>.
778    * @return <jk>true</jk> if this parameter can be resolved, <jk>false</jk> otherwise.
779    */
780   public boolean canResolve(BeanStore beanStore, Object... otherBeans) {
781      var pt = getParameterType();
782
783      // @Value sites resolve from Settings/Env, not the bean store — always considered resolvable
784      // here. (Mutual-exclusion with @Inject is enforced in resolveValue(...).)
785      if (ValueResolver.hasValueAnnotation(getAnnotations()))
786         return true;
787
788      if (pt.is(Optional.class) || pt.isInjectCollectionType()) // Optional/Collection/array types are always satisfied (even if empty).
789         return true;
790
791      var bq = getResolvedQualifier();
792
793      if (nn(bq))
794         return beanStore.hasBean(pt.inner(), bq);
795
796      if (beanStore.hasBean(pt.inner()))
797         return true;
798
799      for (var o : otherBeans)
800         if (canAccept(o))
801            return true;
802      return false;
803   }
804
805   /**
806    * Returns the missing type name if this parameter cannot be resolved, <jk>null</jk> otherwise.
807    *
808    * <p>
809    * The following parameter types are considered optional and always return <jk>null</jk>:
810    * <ul>
811    *    <li>Parameters of type <c>Optional&lt;T&gt;</c>
812    *    <li>Parameters of type <c>T[]</c>, <c>List&lt;T&gt;</c>, <c>Set&lt;T&gt;</c>, or <c>Map&lt;String,T&gt;</c>
813    * </ul>
814    *
815    * <p>
816    * If a parameter has a <ja>@Named</ja> or <ja>@Qualifer</ja> annotation,
817    * the method checks for a bean with that specific name in the bean store.  Otherwise, it checks for an unnamed bean
818    * of the parameter type in the bean store, and if not found, checks the <c>otherBeans</c> parameter.
819    *
820    * @param beanStore The bean store to check for beans.
821    * @param otherBeans Optional additional bean instances to check if not found in the bean store.
822    *    These are checked after the bean store but before marking the parameter as missing.
823    * @return Missing type name (e.g., <js>"String"</js> or <js>"String@name"</js> for qualified beans) or <jk>null</jk> if resolvable.
824    */
825   public String getMissingType(BeanStore beanStore, Object... otherBeans) {
826      var pt = getParameterType();
827      if (ValueResolver.hasValueAnnotation(getAnnotations()))
828         return null;
829      if (pt.is(Optional.class) || pt.isInjectCollectionType()) // Optional/Collection/array types are always satisfied (even if empty).
830         return null;
831      var bq = getResolvedQualifier();  // Use @Named/@Qualified for bean injection
832      if (nn(bq)) {
833         if (! beanStore.hasBean(pt.inner(), bq))
834            return pt.getNameSimple() + '@' + bq;
835         return null;
836      }
837      if (beanStore.hasBean(pt.inner()))
838         return null;
839      for (var o : otherBeans)
840         if (canAccept(o))
841            return null;
842      return pt.getNameSimple();
843   }
844
845   /**
846    * Resolves the parameter value from the bean store.
847    *
848    * <p>
849    * For each parameter, this method:
850    * <ul>
851    *    <li>If the parameter is a collection/array/map type, collects all beans of the element type.
852    *    <li>Otherwise, looks up a single bean by type and optional qualifier name in the bean store.
853    *    <li>If not found in the bean store, checks the <c>otherBeans</c> parameter.
854    * </ul>
855    *
856    * <h5 class='section'>Parameter Resolution:</h5>
857    * <ul class='spaced-list'>
858    *    <li><b>Single beans</b> - Resolved using {@link BeanStore#getBean(Class)} or {@link BeanStore#getBean(Class, String)}.
859    *       If not found, checks <c>otherBeans</c> for a compatible instance.
860    *       Throws {@link ExecutableException} if not found in either location.
861    *    <li><b>Optional beans</b> - Wrapped in <c>Optional</c>, or <c>Optional.empty()</c> if not found.
862    *       Never throws an exception.
863    *    <li><b>Arrays</b> - All beans of the element type are collected into an array (may be empty).
864    *       Never throws an exception.
865    *    <li><b>Lists</b> - All beans of the element type are collected into a <c>List</c> (may be empty).
866    *       Never throws an exception.
867    *    <li><b>Sets</b> - All beans of the element type are collected into a <c>LinkedHashSet</c> (may be empty).
868    *       Never throws an exception.
869    *    <li><b>Maps</b> - All beans of the value type are collected into a <c>LinkedHashMap</c> keyed by bean name (may be empty).
870    *       Unnamed beans use an empty string as the key.  Never throws an exception.
871    * </ul>
872    *
873    * @param beanStore The bean store to resolve beans from.
874    * @param otherBeans Optional additional bean instances to use if not found in the bean store.
875    *    These are checked after the bean store but before throwing an exception.
876    * @return The resolved parameter value.
877    * @throws ExecutableException If a required parameter (non-Optional, non-collection) cannot be resolved
878    *    from the bean store or <c>otherBeans</c>.
879    */
880   
881   @SuppressWarnings({
882      "java:S3776", // Cognitive complexity acceptable for this specific logic
883      "java:S6541" // Single-threaded context; synchronization unnecessary
884   })
885   public Object resolveValue(BeanStore beanStore, Object... otherBeans) {
886      var pt = getParameterType();
887      var bq = getResolvedQualifier();
888      var ptu = pt.unwrap(Optional.class);
889
890      // @Value sites resolve from Settings/VarResolver, not the bean store.
891      var annos = getAnnotations();
892      var valueExpr = ValueResolver.findValueExpression(annos);
893      if (valueExpr != null) {
894         ValueResolver.checkInjectConflict(annos, this.toString());
895         // Pass the declared (generic) parameter type so @Value Supplier<String> autodetects
896         // Supplier<String> field/parameter type opts in to re-evaluating reads.
897         // BeanStore is forwarded so caller-scoped PropertySource beans (e.g. per-RestContext
898         // @Rest(config=...) Configs) participate in expression resolution alongside Settings.
899         var resolved = ValueResolver.resolve(valueExpr, ptu.inner(), inner.getParameterizedType(), this.toString(), beanStore);
900         // Mirror FieldInfo.inject: wrap in Optional when the declared parameter type is Optional<T>.
901         // VarResolver substitutes "" for a missing key with no default — collapse both null and ""
902         // to Optional.empty() so @Value("${maybe}") Optional<T> behaves the same as Spring's.
903         if (pt.is(Optional.class))
904            return (resolved == null || (resolved instanceof String resolved2 && resolved2.isEmpty()))
905               ? oe()
906               : o(resolved);
907         return resolved;
908      }
909
910      if (JsrSupport.isProviderType(ptu.inner())) {
911         var valueType = ptu.innerType() instanceof ParameterizedType parameterizedType
912            && parameterizedType.getActualTypeArguments().length == 1
913            && parameterizedType.getActualTypeArguments()[0] instanceof Class<?> c
914               ? c
915               : Object.class;
916         var supplier = (Supplier<Object>)() -> beanStore.getBean((Class<Object>)valueType, bq).orElse(null);
917         var providerType = ptu.inner();
918         if (eq(providerType.getName(), JsrSupport.JUNEAU_PROVIDER))
919            return (Provider<Object>)supplier::get;
920         var handler = (InvocationHandler)(proxy, method, args) -> {
921            if (eq(method.getName(), "get") && method.getParameterCount() == 0)
922               return supplier.get();
923            if (eq(method.getName(), "toString") && method.getParameterCount() == 0)
924               return providerType.getSimpleName() + "(" + valueType.getSimpleName() + ")";
925            if (eq(method.getName(), "hashCode") && method.getParameterCount() == 0)
926               return System.identityHashCode(proxy);
927            if (eq(method.getName(), "equals") && method.getParameterCount() == 1)
928               return proxy == args[0];
929            throw exex("Unsupported provider method: %s", method.getName());
930         };
931         return Proxy.newProxyInstance(providerType.getClassLoader(), new Class<?>[] {providerType}, handler);
932      }
933
934      // Handle collections and arrays
935      Object collectionValue = null;
936      if (ptu.isInjectCollectionType()) {
937         // Extract element type from collection/array/map parameter type
938         Class<?> elementType = null;
939
940         // Handle arrays
941         if (ptu.isArray()) {
942            elementType = ptu.getComponentType().inner();
943         } else {
944            // Get the parameterized type
945            Type parameterizedType = getParameterizedType();
946            if (parameterizedType instanceof ParameterizedType parameterizedType2) {
947               var rawType = parameterizedType2.getRawType();
948               // If wrapped in Optional, unwrap it to get the nested type
949               if (rawType instanceof Class<?> rawType2 && rawType2 == Optional.class) {
950                  var typeArgs = parameterizedType2.getActualTypeArguments();
951                  if (typeArgs.length > 0 && typeArgs[0] instanceof ParameterizedType typeArgs2) {
952                     // Optional<List<T>> -> List<T>
953                     parameterizedType = typeArgs2;
954                  } else {
955                     // Optional<SomeClass> - not a collection, elementType remains null
956                     parameterizedType = null;
957                  }
958               }
959            } else if (pt.innerType() instanceof ParameterizedType) {
960               // If pt is already a parameterized type (e.g., List<TestService> after unwrapping Optional),
961               // use pt.innerType() as the parameterizedType
962               parameterizedType = pt.innerType();
963            } else {
964               parameterizedType = null;
965            }
966
967            // Handle List<T> or Set<T>
968            var inner2 = o(ptu.inner()).orElse(Object.class);
969            if (eqa(inner2, List.class, Set.class)) {
970               if (parameterizedType instanceof ParameterizedType parameterizedType2) {
971                  var typeArgs = parameterizedType2.getActualTypeArguments();
972                  if (typeArgs.length > 0 && typeArgs[0] instanceof Class<?> elementClass) {
973                     elementType = elementClass;
974                  }
975               }
976            } else if (eq(inner2, Map.class) && parameterizedType instanceof ParameterizedType parameterizedType2) {
977               // Handle Map<String,T> - extract value type (second type argument)
978               var typeArgs = parameterizedType2.getActualTypeArguments();
979               // Verify key type is String and get value type
980               if (typeArgs.length >= 2 && typeArgs[0] == String.class && typeArgs[1] instanceof Class<?> valueClass) {
981                  elementType = valueClass;
982               }
983            }
984         }
985
986         collectionValue = ReflectionUtils.resolveCollectionValue(elementType, beanStore, ptu);
987      }
988      if (nn(collectionValue))
989         return pt.is(Optional.class) ? o(collectionValue) : collectionValue;
990
991      // Handle single bean
992      var ptc = ptu.inner();
993
994      Optional<Object> r;
995
996      if (nn(bq)) {
997         r = beanStore.getBean(ptc, bq);
998      } else {
999         r = beanStore.getBean(ptc);
1000         if (r.isEmpty()) {
1001            for (var r2 : otherBeans)
1002               if (canAccept(r2)) {
1003                  r = o(r2);
1004                  break;
1005               }
1006         }
1007      }
1008
1009      if (pt.is(Optional.class))
1010         return r;
1011      if (r.isPresent())
1012         return r.get();
1013
1014      throw exex("Could not resolve value for parameter %s", this);
1015   }
1016
1017   /**
1018    * Resolves the parameter value from the bean store (constructor version with enclosingInstance).
1019    *
1020    * <p>
1021    * This method is used for constructor parameters.  If the first parameter type matches the <c>enclosingInstance</c>
1022    * object type, it uses the <c>enclosingInstance</c> object (for non-static inner class constructors).
1023    * Otherwise, it delegates to {@link #resolveValue(BeanStore, Object...)}.
1024    *
1025    * @param beanStore The bean store to resolve beans from.
1026    * @param enclosingInstance The outer class instance for non-static inner class constructors.
1027    *    If the first parameter type matches this object's type, it is used as the first parameter value.
1028    *    Can be <jk>null</jk> for regular classes or static inner classes.
1029    * @param otherBeans Optional additional bean instances to use if not found in the bean store.
1030    *    These are checked after the bean store but before throwing an exception.
1031    * @return The resolved parameter value.
1032    * @throws ExecutableException If a required parameter (non-Optional, non-collection) cannot be resolved
1033    *    from the bean store or <c>otherBeans</c>.
1034    */
1035   public Object resolveValue(BeanStore beanStore, Object enclosingInstance, Object... otherBeans) {
1036      var pt = getParameterType();
1037      if (getIndex() == 0 && nn(enclosingInstance) && pt.isInstance(enclosingInstance))
1038         return enclosingInstance;
1039      return resolveValue(beanStore, otherBeans);
1040   }
1041}