001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau.reflect;
014
015import java.lang.annotation.*;
016import java.lang.reflect.*;
017
018import org.apache.juneau.*;
019import org.apache.juneau.annotation.*;
020
021/**
022 * Lightweight utility class for introspecting information about a constructor.
023 */
024@BeanIgnore
025public final class ConstructorInfo extends ExecutableInfo implements Comparable<ConstructorInfo> {
026
027   private final Constructor<?> c;
028
029   //-----------------------------------------------------------------------------------------------------------------
030   // Instantiation.
031   //-----------------------------------------------------------------------------------------------------------------
032
033   /**
034    * Constructor.
035    *
036    * @param declaringClass The class that declares this method.
037    * @param c The constructor being wrapped.
038    * @param rc The "real" constructor if the constructor above is defined against a CGLIB proxy.
039    */
040   protected ConstructorInfo(ClassInfo declaringClass, Constructor<?> c, Constructor<?> rc) {
041      super(declaringClass, c, rc);
042      this.c = c;
043   }
044
045   /**
046    * Convenience method for instantiating a {@link ConstructorInfo};
047    *
048    * @param declaringClass The class that declares this method.
049    * @param c The constructor being wrapped.
050    * @param rc The "real" constructor if the constructor above is defined against a CGLIB proxy.
051    * @return A new {@link ConstructorInfo} object, or <jk>null</jk> if the method was null;
052    */
053   public static ConstructorInfo of(ClassInfo declaringClass, Constructor<?> c, Constructor<?> rc) {
054      if (c == null)
055         return null;
056      return new ConstructorInfo(declaringClass, c, rc);
057   }
058
059   /**
060    * Convenience method for instantiating a {@link ConstructorInfo};
061    *
062    * @param c The constructor being wrapped.
063    * @return A new {@link ConstructorInfo} object, or <jk>null</jk> if the method was null;
064    */
065   public static ConstructorInfo of(Constructor<?> c) {
066      if (c == null)
067         return null;
068      return new ConstructorInfo(ClassInfo.of(c.getDeclaringClass()), c, c);
069   }
070
071   /**
072    * Returns the wrapped method.
073    *
074    * @return The wrapped method.
075    */
076   @SuppressWarnings("unchecked")
077   public <T> Constructor<T> inner() {
078      return (Constructor<T>)c;
079   }
080
081
082   //-----------------------------------------------------------------------------------------------------------------
083   // Annotations
084   //-----------------------------------------------------------------------------------------------------------------
085
086   /**
087    * Finds the annotation of the specified type defined on this constructor.
088    *
089    * @param a
090    *    The annotation to search for.
091    * @return
092    *    The annotation if found, or <jk>null</jk> if not.
093    */
094   public final <T extends Annotation> T getAnnotation(Class<T> a) {
095      return getAnnotation(a, MetaProvider.DEFAULT);
096   }
097
098   /**
099    * Finds the annotation of the specified type defined on this constructor.
100    *
101    * @param a
102    *    The annotation to search for.
103    * @param mp
104    *    The meta provider for looking up annotations on classes/methods/fields.
105    * @return
106    *    The first annotation found, or <jk>null</jk> if it doesn't exist.
107    */
108   public final <T extends Annotation> T getAnnotation(Class<T> a, MetaProvider mp) {
109      return mp.getAnnotation(a, c);
110   }
111
112   /**
113    * Returns <jk>true</jk> if the specified annotation is present on this constructor.
114    *
115    * @param a The annotation to check for.
116    * @return <jk>true</jk> if the specified annotation is present on this constructor.
117    */
118   public final boolean hasAnnotation(Class<? extends Annotation> a) {
119      return getAnnotation(a) != null;
120   }
121
122
123   //-----------------------------------------------------------------------------------------------------------------
124   // Other methods
125   //-----------------------------------------------------------------------------------------------------------------
126
127   /**
128    * Shortcut for calling the new-instance method on the underlying constructor.
129    *
130    * @param args the arguments used for the method call
131    * @return The object returned from the constructor.
132    * @throws ExecutableException Exception occurred on invoked constructor/method/field.
133    */
134   @SuppressWarnings("unchecked")
135   public <T> T invoke(Object...args) throws ExecutableException {
136      try {
137         return (T)c.newInstance(args);
138      } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
139         throw new ExecutableException(e);
140      }
141   }
142
143   /**
144    * Makes constructor accessible if it matches the visibility requirements, or returns <jk>null</jk> if it doesn't.
145    *
146    * <p>
147    * Security exceptions thrown on the call to {@link Constructor#setAccessible(boolean)} are quietly ignored.
148    *
149    * @param v The minimum visibility.
150    * @return
151    *    The same constructor if visibility requirements met, or <jk>null</jk> if visibility requirement not
152    *    met or call to {@link Constructor#setAccessible(boolean)} throws a security exception.
153    */
154   public ConstructorInfo makeAccessible(Visibility v) {
155      if (v.transform(c) == null)
156         return null;
157      return this;
158   }
159
160   @Override
161   public int compareTo(ConstructorInfo o) {
162      int i = getSimpleName().compareTo(o.getSimpleName());
163      if (i == 0) {
164         i = getParamCount() - o.getParamCount();
165         if (i == 0) {
166            for (int j = 0; j < getParamCount() && i == 0; j++) {
167               Class<?>[] tpt = rawParamTypes(), opt = o.rawParamTypes();
168               i = tpt[j].getName().compareTo(opt[j].getName());
169            }
170         }
171      }
172      return i;
173   }
174}