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.utils.AssertionUtils.*;
020import static org.apache.juneau.commons.utils.ThrowableUtils.*;
021import static org.apache.juneau.commons.utils.Utils.*;
022
023import java.lang.reflect.*;
024
025import org.apache.juneau.commons.utils.*;
026
027/**
028 * Lightweight utility class for introspecting information about a Java constructor.
029 *
030 * <p>
031 * This class provides a convenient wrapper around {@link Constructor} that extends the standard Java reflection
032 * API with additional functionality for constructor introspection, annotation handling, and instance creation.
033 * It extends {@link ExecutableInfo} to provide common functionality shared with methods.
034 *
035 * <h5 class='section'>Features:</h5>
036 * <ul class='spaced-list'>
037 *    <li>Constructor introspection - access constructor metadata, parameters, exceptions
038 *    <li>Annotation support - get annotations declared on the constructor
039 *    <li>Instance creation - create new instances with type safety
040 *    <li>Accessibility control - make private constructors accessible
041 *    <li>Thread-safe - instances are immutable and safe for concurrent access
042 * </ul>
043 *
044 * <h5 class='section'>Use Cases:</h5>
045 * <ul class='spaced-list'>
046 *    <li>Introspecting constructor metadata for code generation or analysis
047 *    <li>Creating instances of classes dynamically
048 *    <li>Finding annotations on constructors
049 *    <li>Working with constructor parameters and exceptions
050 *    <li>Building frameworks that need to instantiate objects
051 * </ul>
052 *
053 * <h5 class='section'>Usage:</h5>
054 * <p class='bjava'>
055 *    <jc>// Get ConstructorInfo from a class</jc>
056 *    ClassInfo <jv>ci</jv> = ClassInfo.<jsm>of</jsm>(MyClass.<jk>class</jk>);
057 *    ConstructorInfo <jv>ctor</jv> = <jv>ci</jv>.getConstructor(String.<jk>class</jk>);
058 *
059 *    <jc>// Get annotations</jc>
060 *    List&lt;AnnotationInfo&lt;MyAnnotation&gt;&gt; <jv>annotations</jv> =
061 *       <jv>ctor</jv>.getAnnotations(MyAnnotation.<jk>class</jk>).toList();
062 *
063 *    <jc>// Create instance</jc>
064 *    <jv>ctor</jv>.accessible();  <jc>// Make accessible if private</jc>
065 *    MyClass <jv>obj</jv> = <jv>ctor</jv>.invoke(<js>"arg"</js>);
066 * </p>
067 *
068 * <h5 class='section'>See Also:</h5><ul>
069 *    <li class='jc'>{@link ClassInfo} - Class introspection
070 *    <li class='jc'>{@link MethodInfo} - Method introspection
071 *    <li class='jc'>{@link FieldInfo} - Field introspection
072 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauCommonsReflection">Reflection Package</a>
073 * </ul>
074 */
075public class ConstructorInfo extends ExecutableInfo implements Comparable<ConstructorInfo>, Annotatable {
076
077   /**
078    * Creates a ConstructorInfo wrapper for the specified constructor.
079    *
080    * <h5 class='section'>Example:</h5>
081    * <p class='bjava'>
082    *    ClassInfo <jv>ci</jv> = ClassInfo.<jsm>of</jsm>(MyClass.<jk>class</jk>);
083    *    Constructor&lt;?&gt; <jv>c</jv> = MyClass.<jk>class</jk>.getConstructor(String.<jk>class</jk>);
084    *    ConstructorInfo <jv>ci2</jv> = ConstructorInfo.<jsm>of</jsm>(<jv>ci</jv>, <jv>c</jv>);
085    * </p>
086    *
087    * @param declaringClass The ClassInfo for the class that declares this constructor. Must not be <jk>null</jk>.
088    * @param inner The constructor being wrapped. Must not be <jk>null</jk>.
089    * @return A new ConstructorInfo object wrapping the constructor.
090    */
091   public static ConstructorInfo of(ClassInfo declaringClass, Constructor<?> inner) {
092      assertArgNotNull("declaringClass", declaringClass);
093      return declaringClass.getConstructor(inner);
094   }
095
096   /**
097    * Creates a ConstructorInfo wrapper for the specified constructor.
098    *
099    * <p>
100    * This convenience method automatically determines the declaring class from the constructor.
101    *
102    * <h5 class='section'>Example:</h5>
103    * <p class='bjava'>
104    *    Constructor&lt;?&gt; <jv>c</jv> = MyClass.<jk>class</jk>.getConstructor(String.<jk>class</jk>);
105    *    ConstructorInfo <jv>ci</jv> = ConstructorInfo.<jsm>of</jsm>(<jv>c</jv>);
106    * </p>
107    *
108    * @param inner The constructor being wrapped. Must not be <jk>null</jk>.
109    * @return A new ConstructorInfo object wrapping the constructor.
110    */
111   public static ConstructorInfo of(Constructor<?> inner) {
112      assertArgNotNull("inner", inner);
113      return ClassInfo.of(inner.getDeclaringClass()).getConstructor(inner);
114   }
115
116   private final Constructor<?> inner;
117
118   /**
119    * Constructor.
120    *
121    * <p>
122    * Creates a new ConstructorInfo wrapper for the specified constructor. This constructor is protected
123    * and should not be called directly. Use the static factory methods {@link #of(Constructor)} or
124    * obtain ConstructorInfo instances from {@link ClassInfo#getConstructor(Constructor)}.
125    *
126    * @param declaringClass The ClassInfo for the class that declares this constructor.
127    * @param inner The constructor being wrapped.
128    */
129   protected ConstructorInfo(ClassInfo declaringClass, Constructor<?> inner) {
130      super(declaringClass, inner);
131      this.inner = inner;
132   }
133
134   @Override /* Overridden from ExecutableInfo */
135   public ConstructorInfo accessible() {
136      super.accessible();
137      return this;
138   }
139
140   @Override
141   public int compareTo(ConstructorInfo o) {
142      int i = cmp(getSimpleName(), o.getSimpleName());
143      if (i == 0) {
144         i = getParameterCount() - o.getParameterCount();
145         if (i == 0) {
146            var params = getParameters();
147            var oParams = o.getParameters();
148            for (var j = 0; j < params.size() && i == 0; j++) {
149               i = cmp(params.get(j).getParameterType().getName(), oParams.get(j).getParameterType().getName());
150            }
151         }
152      }
153      return i;
154   }
155
156   @Override /* Annotatable */
157   public AnnotatableType getAnnotatableType() { return AnnotatableType.CONSTRUCTOR_TYPE; }
158
159   @Override /* Annotatable */
160   public String getLabel() { return getDeclaringClass().getNameSimple() + "." + getShortName(); }
161
162   /**
163    * Returns the wrapped constructor.
164    *
165    * <h5 class='section'>Example:</h5>
166    * <p class='bjava'>
167    *    ConstructorInfo <jv>ci</jv> = ...;
168    *    Constructor&lt;MyClass&gt; <jv>ctor</jv> = <jv>ci</jv>.inner();
169    * </p>
170    *
171    * @param <T> The class type of the constructor.
172    * @return The wrapped constructor.
173    */
174   @SuppressWarnings("unchecked")
175   public <T> Constructor<T> inner() {
176      return (Constructor<T>)inner;
177   }
178
179   /**
180    * Compares this ConstructorInfo with the specified object for equality.
181    *
182    * <p>
183    * Two ConstructorInfo objects are considered equal if they wrap the same underlying {@link Constructor} object.
184    * This delegates to the underlying {@link Constructor#equals(Object)} method.
185    *
186    * <p>
187 * This method makes ConstructorInfo suitable for use as keys in hash-based collections such as {@link java.util.HashMap}
188 * and {@link java.util.HashSet}.
189    *
190    * @param obj The object to compare with.
191    * @return <jk>true</jk> if the objects are equal, <jk>false</jk> otherwise.
192    */
193   @Override
194   public boolean equals(Object obj) {
195      return obj instanceof ConstructorInfo other && eq(this, other, (x, y) -> eq(x.inner, y.inner));
196   }
197
198   /**
199    * Returns a hash code value for this ConstructorInfo.
200    *
201    * <p>
202    * This delegates to the underlying {@link Constructor#hashCode()} method.
203    *
204    * <p>
205 * This method makes ConstructorInfo suitable for use as keys in hash-based collections such as {@link java.util.HashMap}
206 * and {@link java.util.HashSet}.
207    *
208    * @return A hash code value for this ConstructorInfo.
209    */
210   @Override
211   public int hashCode() {
212      return inner.hashCode();
213   }
214
215   /**
216    * Shortcut for calling the new-instance method on the underlying constructor.
217    *
218    * @param <T> The constructor class type.
219    * @param args the arguments used for the method call.
220    * @return The object returned from the constructor.
221    * @throws ExecutableException Exception occurred on invoked constructor/method/field.
222    */
223   @SuppressWarnings("unchecked")
224   public <T> T newInstance(Object...args) throws ExecutableException {
225      return safe(() -> {
226         try {
227            return (T)inner.newInstance(args);
228         } catch (InvocationTargetException e) {
229            throw exex(e.getTargetException());
230         }
231      }, e -> exex(e));  // HTT
232   }
233
234   /**
235    * Shortcut for calling the new-instance method on the underlying constructor using lenient argument matching.
236    *
237    * <p>
238    * Lenient matching allows arguments to be matched to parameters based on parameter types.
239    * <br>Arguments can be in any order.
240    * <br>Extra arguments are ignored.
241    * <br>Missing arguments are set to <jk>null</jk>.
242    *
243    * @param <T> The constructor class type.
244    * @param args The arguments used for the constructor call.
245    * @return The object returned from the constructor.
246    * @throws ExecutableException Exception occurred on invoked constructor/method/field.
247    */
248   public <T> T newInstanceLenient(Object...args) throws ExecutableException {
249      return newInstance(ClassUtils.getMatchingArgs(inner.getParameterTypes(), args));
250   }
251   //-----------------------------------------------------------------------------------------------------------------
252   // Annotatable interface methods
253   //-----------------------------------------------------------------------------------------------------------------
254}