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 java.util.stream.Collectors.*;
020import static org.apache.juneau.commons.utils.Shorts.*;
021import static org.apache.juneau.commons.utils.StringUtils.*;
022import static org.apache.juneau.commons.utils.ThrowableUtils.*;
023
024import java.lang.reflect.*;
025import java.util.*;
026
027import org.apache.juneau.commons.inject.*;
028import org.apache.juneau.commons.utils.*;
029
030/**
031 * Lightweight utility class for introspecting information about a Java constructor.
032 *
033 * <p>
034 * This class provides a convenient wrapper around {@link Constructor} that extends the standard Java reflection
035 * API with additional functionality for constructor introspection, annotation handling, and instance creation.
036 * It extends {@link ExecutableInfo} to provide common functionality shared with methods.
037 *
038 * <h5 class='section'>Features:</h5>
039 * <ul class='spaced-list'>
040 *    <li>Constructor introspection - access constructor metadata, parameters, exceptions
041 *    <li>Annotation support - get annotations declared on the constructor
042 *    <li>Instance creation - create new instances with type safety
043 *    <li>Accessibility control - make private constructors accessible
044 *    <li>Thread-safe - instances are immutable and safe for concurrent access
045 * </ul>
046 *
047 * <h5 class='section'>Use Cases:</h5>
048 * <ul class='spaced-list'>
049 *    <li>Introspecting constructor metadata for code generation or analysis
050 *    <li>Creating instances of classes dynamically
051 *    <li>Finding annotations on constructors
052 *    <li>Working with constructor parameters and exceptions
053 *    <li>Building frameworks that need to instantiate objects
054 * </ul>
055 *
056 * <h5 class='section'>Usage:</h5>
057 * <p class='bjava'>
058 *    <jc>// Get ConstructorInfo from a class</jc>
059 *    ClassInfo <jv>ci</jv> = ClassInfo.<jsm>of</jsm>(MyClass.<jk>class</jk>);
060 *    ConstructorInfo <jv>ctor</jv> = <jv>ci</jv>.getConstructor(String.<jk>class</jk>);
061 *
062 *    <jc>// Get annotations</jc>
063 *    List&lt;AnnotationInfo&lt;MyAnnotation&gt;&gt; <jv>annotations</jv> =
064 *       <jv>ctor</jv>.getAnnotations(MyAnnotation.<jk>class</jk>).toList();
065 *
066 *    <jc>// Create instance</jc>
067 *    <jv>ctor</jv>.accessible();  <jc>// Make accessible if private</jc>
068 *    MyClass <jv>obj</jv> = <jv>ctor</jv>.invoke(<js>"arg"</js>);
069 * </p>
070 *
071 * <h5 class='section'>See Also:</h5><ul>
072 *    <li class='jc'>{@link ClassInfo} - Class introspection
073 *    <li class='jc'>{@link MethodInfo} - Method introspection
074 *    <li class='jc'>{@link FieldInfo} - Field introspection
075 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauCommonsReflection">Reflection Package</a>
076 * </ul>
077 */
078@SuppressWarnings({
079   "java:S1192", // Duplicated literals (argument/property names) read more clearly inline than as constants
080   "unchecked" // (T) cast of Constructor.newInstance() in the generic newInstance(): T is chosen by the caller to be the constructor's declaring type
081})
082public final class ConstructorInfo extends ExecutableInfo implements Comparable<ConstructorInfo>, Annotatable {
083
084   /**
085    * Creates a ConstructorInfo wrapper for the specified constructor.
086    *
087    * <h5 class='section'>Example:</h5>
088    * <p class='bjava'>
089    *    ClassInfo <jv>ci</jv> = ClassInfo.<jsm>of</jsm>(MyClass.<jk>class</jk>);
090    *    Constructor&lt;?&gt; <jv>c</jv> = MyClass.<jk>class</jk>.getConstructor(String.<jk>class</jk>);
091    *    ConstructorInfo <jv>ci2</jv> = ConstructorInfo.<jsm>of</jsm>(<jv>ci</jv>, <jv>c</jv>);
092    * </p>
093    *
094    * @param declaringClass The ClassInfo for the class that declares this constructor. Must not be <jk>null</jk>.
095    * @param inner The constructor being wrapped. Must not be <jk>null</jk>.
096    * @return A new ConstructorInfo object wrapping the constructor.
097    */
098   public static ConstructorInfo of(ClassInfo declaringClass, Constructor<?> inner) {
099      reqnn("declaringClass", declaringClass);
100      return declaringClass.getConstructor(inner);
101   }
102
103   /**
104    * Creates a ConstructorInfo wrapper for the specified constructor.
105    *
106    * <p>
107    * This convenience method automatically determines the declaring class from the constructor.
108    *
109    * <h5 class='section'>Example:</h5>
110    * <p class='bjava'>
111    *    Constructor&lt;?&gt; <jv>c</jv> = MyClass.<jk>class</jk>.getConstructor(String.<jk>class</jk>);
112    *    ConstructorInfo <jv>ci</jv> = ConstructorInfo.<jsm>of</jsm>(<jv>c</jv>);
113    * </p>
114    *
115    * @param inner The constructor being wrapped. Must not be <jk>null</jk>.
116    * @return A new ConstructorInfo object wrapping the constructor.
117    */
118   public static ConstructorInfo of(Constructor<?> inner) {
119      reqnn("inner", inner);
120      return ClassInfo.of(inner.getDeclaringClass()).getConstructor(inner);
121   }
122
123   private final Constructor<?> inner;
124
125   /**
126    * Constructor.
127    *
128    * <p>
129    * Creates a new ConstructorInfo wrapper for the specified constructor. This constructor is protected
130    * and should not be called directly. Use the static factory methods {@link #of(Constructor)} or
131    * obtain ConstructorInfo instances from {@link ClassInfo#getConstructor(Constructor)}.
132    *
133    * @param declaringClass The ClassInfo for the class that declares this constructor. Must not be <jk>null</jk>.
134    * @param inner The constructor being wrapped. Must not be <jk>null</jk>.
135    */
136   protected ConstructorInfo(ClassInfo declaringClass, Constructor<?> inner) {
137      super(declaringClass, inner);
138      this.inner = inner;
139   }
140
141   @Override /* Overridden from ExecutableInfo */
142   public ConstructorInfo accessible() {
143      super.accessible();
144      return this;
145   }
146
147   @Override
148   public int compareTo(ConstructorInfo o) {
149      int i = cmp(getNameSimple(), o.getNameSimple());
150      if (i == 0) {
151         i = getParameterCount() - o.getParameterCount();
152         if (i == 0) {
153            var params = getParameters();
154            var oParams = o.getParameters();
155            for (var j = 0; j < params.size() && i == 0; j++) {
156               i = cmp(params.get(j).getParameterType().getName(), oParams.get(j).getParameterType().getName());
157            }
158         }
159      }
160      return i;
161   }
162
163   @Override /* Annotatable */
164   public AnnotatableType getAnnotatableType() { return AnnotatableType.CONSTRUCTOR_TYPE; }
165
166   @Override /* Annotatable */
167   public String getLabel() { return getDeclaringClass().getNameSimple() + "." + getNameShort(); }
168
169   /**
170    * Returns the wrapped constructor.
171    *
172    * <h5 class='section'>Example:</h5>
173    * <p class='bjava'>
174    *    ConstructorInfo <jv>ci</jv> = ...;
175    *    Constructor&lt;MyClass&gt; <jv>ctor</jv> = <jv>ci</jv>.inner();
176    * </p>
177    *
178    * @param <T> The class type of the constructor.
179    * @return The wrapped constructor.
180    */
181   public <T> Constructor<T> inner() {
182      return (Constructor<T>)inner;
183   }
184
185   /**
186    * Compares this ConstructorInfo with the specified object for equality.
187    *
188    * <p>
189    * Two ConstructorInfo objects are considered equal if they wrap the same underlying {@link Constructor} object.
190    * This delegates to the underlying {@link Constructor#equals(Object)} method.
191    *
192    * <p>
193 * This method makes ConstructorInfo suitable for use as keys in hash-based collections such as {@link HashMap}
194 * and {@link HashSet}.
195    *
196    * @param obj The object to compare with.
197    * @return <jk>true</jk> if the objects are equal, <jk>false</jk> otherwise.
198    */
199   @Override
200   public boolean equals(Object obj) {
201      return obj instanceof ConstructorInfo obj2 && eq(this, obj2, (x, y) -> eq(x.inner, y.inner));
202   }
203
204   /**
205    * Returns a hash code value for this ConstructorInfo.
206    *
207    * <p>
208    * This delegates to the underlying {@link Constructor#hashCode()} method.
209    *
210    * <p>
211 * This method makes ConstructorInfo suitable for use as keys in hash-based collections such as {@link HashMap}
212 * and {@link HashSet}.
213    *
214    * @return A hash code value for this ConstructorInfo.
215    */
216   @Override
217   public int hashCode() {
218      return inner.hashCode();
219   }
220
221   /**
222    * Shortcut for calling the new-instance method on the underlying constructor.
223    *
224    * <p>
225    * If the number of formal parameters required by the underlying constructor is 0, the supplied <c>args</c> array may be of length 0 or <jk>null</jk>.
226    *
227    * @param <T> The constructor class type.
228    * @param args The arguments used for the constructor call.  Can be <jk>null</jk> or empty for constructors with no parameters.
229    * @return The object returned from the constructor.
230    * @throws ExecutableException Exception occurred on invoked constructor/method/field.
231    */
232   public <T> T newInstance(Object...args) throws ExecutableException {
233      return safe(() -> {
234         try {
235            return (T)inner.newInstance(args);
236         } catch (InvocationTargetException e) {
237            throw exex(e.getTargetException());
238         }
239      }, Shorts::exex);  // HTT
240   }
241
242   /**
243    * Shortcut for calling the new-instance method on the underlying constructor using lenient argument matching.
244    *
245    * <p>
246    * Lenient matching allows arguments to be matched to parameters based on parameter types.
247    * <br>Arguments can be in any order.
248    * <br>Extra arguments are ignored.
249    * <br>Missing arguments are set to <jk>null</jk>.
250    *
251    * @param <T> The constructor class type.
252    * @param args The arguments used for the constructor call.
253    * @return The object returned from the constructor.
254    * @throws ExecutableException Exception occurred on invoked constructor/method/field.
255    */
256   public <T> T newInstanceLenient(Object...args) throws ExecutableException {
257      return newInstance(ClassUtils.getMatchingArgs(inner.getParameterTypes(), args));
258   }
259
260   /**
261    * Returns comma-delimited list of missing parameter types.
262    *
263    * <p>
264    * Analyzes the parameters of this constructor and checks if all required beans are available
265    * in the bean store or in the <c>otherBeans</c> parameter.
266    *
267    * <p>
268    * The following parameter types are considered optional and are not checked:
269    * <ul>
270    *    <li>Parameters of type <c>Optional&lt;T&gt;</c>
271    *    <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>
272    *    <li>The first parameter if it matches the <c>enclosingInstance</c> object type (for non-static inner classes)
273    * </ul>
274    *
275    * <p>
276    * If a parameter has a <ja>@Named</ja> or {@code @Qualifier} annotation,
277    * the method checks for a bean with that specific name in the bean store.  Otherwise, it checks for an unnamed bean
278    * of the parameter type in the bean store, and if not found, checks the <c>otherBeans</c> parameter.
279    *
280    * @param beanStore The bean store to check for beans.
281    * @param enclosingInstance The outer class instance for non-static inner class constructors.
282    *    If the first parameter type matches this object's type, it is used as the first parameter and not checked in the bean store.
283    *    Can be <jk>null</jk> for regular classes or static inner classes.
284    * @param otherBeans Optional additional bean instances to check if not found in the bean store.
285    *    These are checked after the bean store but before marking the parameter as missing.
286    * @return A comma-delimited, sorted list of missing parameter types (e.g., <js>"String,Integer"</js>),
287    *    or <jk>null</jk> if all required parameters are available.
288    */
289   public String getMissingParameterTypes(BeanStore beanStore, Object enclosingInstance, Object... otherBeans) {
290      // @formatter:off
291      return nullIfEmpty(
292         getParameters()
293            .stream()
294            .map(x -> {
295               var pt = x.getParameterType();
296               if (x.getIndex() == 0 && nn(enclosingInstance) && pt.isInstance(enclosingInstance))
297                  return null;
298               return x.getMissingType(beanStore, otherBeans);
299            })
300            .filter(Objects::nonNull)
301            .sorted()
302            .collect(joining(","))
303      );
304      // @formatter:on
305   }
306
307   /**
308    * Checks if all constructor parameters can be resolved.
309    *
310    * <p>
311    * This method performs the same checks as {@link #getMissingParameterTypes(BeanStore, Object, Object...)} but
312    * returns a boolean instead of a list of missing types.
313    *
314    * <p>
315    * The following parameter types are considered optional and are not checked:
316    * <ul>
317    *    <li>Parameters of type <c>Optional&lt;T&gt;</c>
318    *    <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>
319    *    <li>The first parameter if it matches the <c>enclosingInstance</c> object type (for non-static inner classes)
320    * </ul>
321    *
322    * <p>
323    * If a parameter has a <ja>@Named</ja> or {@code @Qualifier} annotation,
324    * the method checks for a bean with that specific name in the bean store.  Otherwise, it checks for an unnamed bean
325    * of the parameter type in the bean store, and if not found, checks the <c>otherBeans</c> parameter.
326    *
327    * @param beanStore The bean store to check for beans.
328    * @param enclosingInstance The outer class instance for non-static inner class constructors.
329    *    If the first parameter type matches this object's type, it is used as the first parameter and not checked in the bean store.
330    *    Can be <jk>null</jk> for regular classes or static inner classes.
331    * @param otherBeans Optional additional bean instances to check if not found in the bean store.
332    *    These are checked after the bean store but before marking the parameter as missing.
333    * @return <jk>true</jk> if all required parameters are available in the bean store or <c>otherBeans</c>, <jk>false</jk> otherwise.
334    */
335   public boolean canResolveAllParameters(BeanStore beanStore, Object enclosingInstance, Object... otherBeans) {
336      return getParameters().stream().map(x -> {
337         var pt = x.getParameterType();
338         if (x.getIndex() == 0 && nn(enclosingInstance) && pt.isInstance(enclosingInstance))
339            return true;
340         return x.canResolve(beanStore, otherBeans);
341      }).allMatch(x -> x);
342   }
343
344   /**
345    * Resolves parameters from the bean store and invokes the constructor.
346    *
347    * <p>
348    * For each parameter in the constructor, this method:
349    * <ul>
350    *    <li>If the first parameter type matches the <c>enclosingInstance</c> object type, uses the <c>enclosingInstance</c> object
351    *       (for non-static inner class constructors).
352    *    <li>If the parameter is a collection/array/map type, collects all beans of the element type.
353    *    <li>Otherwise, looks up a single bean by type and optional qualifier name in the bean store.
354    *    <li>If not found in the bean store, checks the <c>otherBeans</c> parameter.
355    * </ul>
356    *
357    * <h5 class='section'>Parameter Resolution:</h5>
358    * <ul class='spaced-list'>
359    *    <li><b>Single beans</b> - Resolved using {@link BeanStore#getBean(Class)} or {@link BeanStore#getBean(Class, String)}.
360    *       If not found, checks <c>otherBeans</c> for a compatible instance.
361    *       Throws {@link ExecutableException} if not found in either location.
362    *    <li><b>Optional beans</b> - Wrapped in <c>Optional</c>, or <c>Optional.empty()</c> if not found.
363    *       Never throws an exception.
364    *    <li><b>Arrays</b> - All beans of the element type are collected into an array (may be empty).
365    *       Never throws an exception.
366    *    <li><b>Lists</b> - All beans of the element type are collected into a <c>List</c> (may be empty).
367    *       Never throws an exception.
368    *    <li><b>Sets</b> - All beans of the element type are collected into a <c>LinkedHashSet</c> (may be empty).
369    *       Never throws an exception.
370    *    <li><b>Maps</b> - All beans of the value type are collected into a <c>LinkedHashMap</c> keyed by bean name (may be empty).
371    *       Unnamed beans use an empty string as the key.  Never throws an exception.
372    * </ul>
373    *
374    * <p>
375    * The <c>enclosingInstance</c> parameter is used for non-static inner class constructors.  If the first parameter type
376    * matches this object's type, it is used as the first parameter value.  For regular constructors, this parameter
377    * is ignored if it doesn't match the first parameter type.
378    *
379    * @param <T> The return type of the constructor.
380    * @param beanStore The bean store to resolve parameters from.
381    * @param enclosingInstance The outer class instance for non-static inner classes (can be <jk>null</jk>).
382    * @param otherBeans Optional additional bean instances to use if not found in the bean store.
383    * @return The result of invoking the constructor.
384    * @throws ExecutableException If the constructor cannot be invoked or parameter resolution fails.
385    */
386   public <T> T inject(BeanStore beanStore, Object enclosingInstance, Object... otherBeans) {
387      var params = getParameters().stream().map(x -> x.resolveValue(beanStore, enclosingInstance, otherBeans)).toArray();
388      return accessible().newInstance(params);
389   }
390
391   /**
392    * Resolves all constructor parameters from the bean store.
393    *
394    * <p>
395    * This is a package-private helper method used by tests.  For normal usage, use {@link #inject(BeanStore, Object, Object...)}.
396    *
397    * @param beanStore The bean store to resolve beans from.
398    * @param enclosingInstance The outer class instance for non-static inner class constructors.
399    * @param otherBeans Optional additional bean instances to use if not found in the bean store.
400    * @return An array of parameter values in the same order as the constructor parameters.
401    * @throws ExecutableException If a required parameter cannot be resolved.
402    */
403   Object[] resolveParameters(BeanStore beanStore, Object enclosingInstance, Object... otherBeans) {
404      return getParameters().stream().map(x -> x.resolveValue(beanStore, enclosingInstance, otherBeans)).toArray();
405   }
406}