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 static org.apache.juneau.internal.ConsumerUtils.*; 016 017import java.lang.annotation.*; 018import java.lang.reflect.*; 019import java.util.function.*; 020 021import org.apache.juneau.*; 022import org.apache.juneau.internal.*; 023 024/** 025 * Lightweight utility class for introspecting information about a constructor. 026 * 027 * <h5 class='section'>See Also:</h5><ul> 028 * </ul> 029 */ 030@FluentSetters 031public final class ConstructorInfo extends ExecutableInfo implements Comparable<ConstructorInfo> { 032 033 //----------------------------------------------------------------------------------------------------------------- 034 // Static 035 //----------------------------------------------------------------------------------------------------------------- 036 037 /** 038 * Convenience method for instantiating a {@link ConstructorInfo}; 039 * 040 * @param declaringClass The class that declares this method. 041 * @param c The constructor being wrapped. 042 * @return A new {@link ConstructorInfo} object, or <jk>null</jk> if the method was null; 043 */ 044 public static ConstructorInfo of(ClassInfo declaringClass, Constructor<?> c) { 045 if (c == null) 046 return null; 047 return ClassInfo.of(declaringClass).getConstructorInfo(c); 048 } 049 050 /** 051 * Convenience method for instantiating a {@link ConstructorInfo}; 052 * 053 * @param c The constructor being wrapped. 054 * @return A new {@link ConstructorInfo} object, or <jk>null</jk> if the method was null; 055 */ 056 public static ConstructorInfo of(Constructor<?> c) { 057 if (c == null) 058 return null; 059 return ClassInfo.of(c.getDeclaringClass()).getConstructorInfo(c); 060 } 061 062 //----------------------------------------------------------------------------------------------------------------- 063 // Instance 064 //----------------------------------------------------------------------------------------------------------------- 065 066 private final Constructor<?> c; 067 068 /** 069 * Constructor. 070 * 071 * @param declaringClass The class that declares this method. 072 * @param c The constructor being wrapped. 073 */ 074 protected ConstructorInfo(ClassInfo declaringClass, Constructor<?> c) { 075 super(declaringClass, c); 076 this.c = c; 077 } 078 079 /** 080 * Returns the wrapped method. 081 * 082 * @param <T> The inner class type. 083 * @return The wrapped method. 084 */ 085 @SuppressWarnings("unchecked") 086 public <T> Constructor<T> inner() { 087 return (Constructor<T>)c; 088 } 089 090 //----------------------------------------------------------------------------------------------------------------- 091 // Annotations 092 //----------------------------------------------------------------------------------------------------------------- 093 094 /** 095 * Finds the annotation of the specified type defined on this constructor. 096 * 097 * @param <A> The annotation type to look for. 098 * @param type The annotation to look for. 099 * @return The annotation if found, or <jk>null</jk> if not. 100 */ 101 public <A extends Annotation> A getAnnotation(Class<A> type) { 102 return getAnnotation(AnnotationProvider.DEFAULT, type); 103 } 104 105 /** 106 * Finds the annotation of the specified type defined on this constructor. 107 * 108 * @param <A> The annotation type to look for. 109 * @param annotationProvider The annotation provider. 110 * @param type The annotation to look for. 111 * @return The first annotation found, or <jk>null</jk> if it doesn't exist. 112 */ 113 public <A extends Annotation> A getAnnotation(AnnotationProvider annotationProvider, Class<A> type) { 114 Value<A> t = Value.empty(); 115 annotationProvider.forEachAnnotation(type, c, x -> true, x -> t.set(x)); 116 return t.orElse(null); 117 } 118 119 /** 120 * Returns <jk>true</jk> if the specified annotation is present on this constructor. 121 * 122 * @param <A> The annotation type to look for. 123 * @param type The annotation to look for. 124 * @return <jk>true</jk> if the specified annotation is present on this constructor. 125 */ 126 public <A extends Annotation> boolean hasAnnotation(Class<A> type) { 127 return hasAnnotation(AnnotationProvider.DEFAULT, type); 128 } 129 130 /** 131 * Returns <jk>true</jk> if the specified annotation is present on this constructor. 132 * 133 * @param <A> The annotation type to look for. 134 * @param annotationProvider The annotation provider. 135 * @param type The annotation to look for. 136 * @return <jk>true</jk> if the specified annotation is present on this constructor. 137 */ 138 public <A extends Annotation> boolean hasAnnotation(AnnotationProvider annotationProvider, Class<A> type) { 139 return annotationProvider.firstAnnotation(type, c, x -> true) != null; 140 } 141 142 /** 143 * Returns <jk>true</jk> if the specified annotation is not present on this constructor. 144 * 145 * @param <A> The annotation type to look for. 146 * @param annotationProvider The annotation provider. 147 * @param type The annotation to look for. 148 * @return <jk>true</jk> if the specified annotation is not present on this constructor. 149 */ 150 public <A extends Annotation> boolean hasNoAnnotation(AnnotationProvider annotationProvider, Class<A> type) { 151 return ! hasAnnotation(annotationProvider, type); 152 } 153 154 //----------------------------------------------------------------------------------------------------------------- 155 // Other methods 156 //----------------------------------------------------------------------------------------------------------------- 157 158 /** 159 * Returns <jk>true</jk> if this object passes the specified predicate test. 160 * 161 * @param test The test to perform. 162 * @return <jk>true</jk> if this object passes the specified predicate test. 163 */ 164 public boolean matches(Predicate<ConstructorInfo> test) { 165 return test(test, this); 166 } 167 168 /** 169 * Performs an action on this object if the specified predicate test passes. 170 * 171 * @param test A test to apply to determine if action should be executed. Can be <jk>null</jk>. 172 * @param action An action to perform on this object. 173 * @return This object. 174 */ 175 public ConstructorInfo accept(Predicate<ConstructorInfo> test, Consumer<ConstructorInfo> action) { 176 if (matches(test)) 177 action.accept(this); 178 return this; 179 } 180 181 /** 182 * Returns <jk>true</jk> if this constructor can accept the specified arguments in the specified order. 183 * 184 * @param args The arguments to check. 185 * @return <jk>true</jk> if this constructor can accept the specified arguments in the specified order. 186 */ 187 public boolean canAccept(Object...args) { 188 Class<?>[] pt = c.getParameterTypes(); 189 if (pt.length != args.length) 190 return false; 191 for (int i = 0; i < pt.length; i++) 192 if (! pt[i].isInstance(args[i])) 193 return false; 194 return true; 195 } 196 197 /** 198 * Shortcut for calling the new-instance method on the underlying constructor. 199 * 200 * @param <T> The constructor class type. 201 * @param args the arguments used for the method call. 202 * <br>Extra parameters are ignored. 203 * <br>Missing parameters are set to null. 204 * @return The object returned from the constructor. 205 * @throws ExecutableException Exception occurred on invoked constructor/method/field. 206 */ 207 public <T> T invokeFuzzy(Object...args) throws ExecutableException { 208 return invoke(ClassUtils.getMatchingArgs(c.getParameterTypes(), args)); 209 } 210 211 /** 212 * Shortcut for calling the new-instance method on the underlying constructor. 213 * 214 * @param <T> The constructor class type. 215 * @param args the arguments used for the method call. 216 * @return The object returned from the constructor. 217 * @throws ExecutableException Exception occurred on invoked constructor/method/field. 218 */ 219 @SuppressWarnings("unchecked") 220 public <T> T invoke(Object...args) throws ExecutableException { 221 try { 222 return (T)c.newInstance(args); 223 } catch (InvocationTargetException e) { 224 throw new ExecutableException(e.getTargetException()); 225 } catch (Exception e) { 226 throw new ExecutableException(e); 227 } 228 } 229 230 /** 231 * Makes constructor accessible if it matches the visibility requirements, or returns <jk>null</jk> if it doesn't. 232 * 233 * <p> 234 * Security exceptions thrown on the call to {@link Constructor#setAccessible(boolean)} are quietly ignored. 235 * 236 * @param v The minimum visibility. 237 * @return 238 * The same constructor if visibility requirements met, or <jk>null</jk> if visibility requirement not 239 * met or call to {@link Constructor#setAccessible(boolean)} throws a security exception. 240 */ 241 public ConstructorInfo accessible(Visibility v) { 242 if (v.transform(c) == null) 243 return null; 244 return this; 245 } 246 247 @Override 248 public int compareTo(ConstructorInfo o) { 249 int i = getSimpleName().compareTo(o.getSimpleName()); 250 if (i == 0) { 251 i = getParamCount() - o.getParamCount(); 252 if (i == 0) { 253 for (int j = 0; j < getParamCount() && i == 0; j++) { 254 Class<?>[] tpt = _getRawParamTypes(), opt = o._getRawParamTypes(); 255 i = tpt[j].getName().compareTo(opt[j].getName()); 256 } 257 } 258 } 259 return i; 260 } 261 262 // <FluentSetters> 263 264 @Override /* GENERATED - org.apache.juneau.reflect.ExecutableInfo */ 265 public ConstructorInfo accessible() { 266 super.accessible(); 267 return this; 268 } 269 270 // </FluentSetters> 271}