1/* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17/* 18 * Copyright (C) 2008 The Android Open Source Project 19 * 20 * Licensed under the Apache License, Version 2.0 (the "License"); 21 * you may not use this file except in compliance with the License. 22 * You may obtain a copy of the License at 23 * 24 * http://www.apache.org/licenses/LICENSE-2.0 25 * 26 * Unless required by applicable law or agreed to in writing, software 27 * distributed under the License is distributed on an "AS IS" BASIS, 28 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 29 * See the License for the specific language governing permissions and 30 * limitations under the License. 31 */ 32 33package java.lang.reflect; 34 35import java.lang.annotation.Annotation; 36import libcore.util.EmptyArray; 37import org.apache.harmony.kernel.vm.StringUtils; 38import org.apache.harmony.luni.lang.reflect.GenericSignatureParser; 39import org.apache.harmony.luni.lang.reflect.ListOfTypes; 40import org.apache.harmony.luni.lang.reflect.Types; 41 42/** 43 * This class represents a constructor. Information about the constructor can be 44 * accessed, and the constructor can be invoked dynamically. 45 * 46 * @param <T> the class that declares this constructor 47 */ 48public final class Constructor<T> extends AccessibleObject implements GenericDeclaration, 49 Member { 50 51 Class<T> declaringClass; 52 53 Class<?>[] parameterTypes; 54 55 Class<?>[] exceptionTypes; 56 57 ListOfTypes genericExceptionTypes; 58 ListOfTypes genericParameterTypes; 59 TypeVariable<Constructor<T>>[] formalTypeParameters; 60 private volatile boolean genericTypesAreInitialized = false; 61 62 private synchronized void initGenericTypes() { 63 if (!genericTypesAreInitialized) { 64 String signatureAttribute = getSignatureAttribute(); 65 GenericSignatureParser parser = new GenericSignatureParser( 66 declaringClass.getClassLoader()); 67 parser.parseForConstructor(this, signatureAttribute, exceptionTypes); 68 formalTypeParameters = parser.formalTypeParameters; 69 genericParameterTypes = parser.parameterTypes; 70 genericExceptionTypes = parser.exceptionTypes; 71 genericTypesAreInitialized = true; 72 } 73 } 74 75 int slot; 76 77 /** 78 * Prevent this class from being instantiated. 79 */ 80 private Constructor(){ 81 //do nothing 82 } 83 84 /** 85 * Creates an instance of the class. Only called from native code, thus 86 * private. 87 * 88 * @param declaringClass 89 * the class this constructor object belongs to 90 * @param ptypes 91 * the parameter types of the constructor 92 * @param extypes 93 * the exception types of the constructor 94 * @param slot 95 * the slot of the constructor inside the VM class structure 96 */ 97 private Constructor (Class<T> declaringClass, Class<?>[] ptypes, Class<?>[] extypes, int slot){ 98 this.declaringClass = declaringClass; 99 this.parameterTypes = ptypes; 100 this.exceptionTypes = extypes; // may be null 101 this.slot = slot; 102 } 103 104 @Override /*package*/ String getSignatureAttribute() { 105 Object[] annotation = Method.getSignatureAnnotation(declaringClass, slot); 106 107 if (annotation == null) { 108 return null; 109 } 110 111 return StringUtils.combineStrings(annotation); 112 } 113 114 public TypeVariable<Constructor<T>>[] getTypeParameters() { 115 initGenericTypes(); 116 return formalTypeParameters.clone(); 117 } 118 119 /** 120 * Returns the string representation of the constructor's declaration, 121 * including the type parameters. 122 * 123 * @return the string representation of the constructor's declaration 124 */ 125 public String toGenericString() { 126 StringBuilder sb = new StringBuilder(80); 127 initGenericTypes(); 128 // append modifiers if any 129 int modifier = getModifiers(); 130 if (modifier != 0) { 131 sb.append(Modifier.toString(modifier & ~Modifier.VARARGS)).append(' '); 132 } 133 // append type parameters 134 if (formalTypeParameters != null && formalTypeParameters.length > 0) { 135 sb.append('<'); 136 for (int i = 0; i < formalTypeParameters.length; i++) { 137 appendGenericType(sb, formalTypeParameters[i]); 138 if (i < formalTypeParameters.length - 1) { 139 sb.append(","); 140 } 141 } 142 sb.append("> "); 143 } 144 // append constructor name 145 appendTypeName(sb, getDeclaringClass()); 146 // append parameters 147 sb.append('('); 148 appendArrayGenericType(sb, 149 Types.getClonedTypeArray(genericParameterTypes)); 150 sb.append(')'); 151 // append exceptions if any 152 Type[] genericExceptionTypeArray = 153 Types.getClonedTypeArray(genericExceptionTypes); 154 if (genericExceptionTypeArray.length > 0) { 155 sb.append(" throws "); 156 appendArrayGenericType(sb, genericExceptionTypeArray); 157 } 158 return sb.toString(); 159 } 160 161 /** 162 * Returns the generic parameter types as an array of {@code Type} 163 * instances, in declaration order. If this constructor has no generic 164 * parameters, an empty array is returned. 165 * 166 * @return the parameter types 167 * 168 * @throws GenericSignatureFormatError 169 * if the generic constructor signature is invalid 170 * @throws TypeNotPresentException 171 * if any parameter type points to a missing type 172 * @throws MalformedParameterizedTypeException 173 * if any parameter type points to a type that cannot be 174 * instantiated for some reason 175 */ 176 public Type[] getGenericParameterTypes() { 177 initGenericTypes(); 178 return Types.getClonedTypeArray(genericParameterTypes); 179 } 180 181 /** 182 * Returns the exception types as an array of {@code Type} instances. If 183 * this constructor has no declared exceptions, an empty array will be 184 * returned. 185 * 186 * @return an array of generic exception types 187 * 188 * @throws GenericSignatureFormatError 189 * if the generic constructor signature is invalid 190 * @throws TypeNotPresentException 191 * if any exception type points to a missing type 192 * @throws MalformedParameterizedTypeException 193 * if any exception type points to a type that cannot be 194 * instantiated for some reason 195 */ 196 public Type[] getGenericExceptionTypes() { 197 initGenericTypes(); 198 return Types.getClonedTypeArray(genericExceptionTypes); 199 } 200 201 @Override 202 public Annotation[] getDeclaredAnnotations() { 203 return Method.getDeclaredAnnotations(declaringClass, slot); 204 } 205 206 @Override public <A extends Annotation> A getAnnotation(Class<A> annotationType) { 207 if (annotationType == null) { 208 throw new NullPointerException("annotationType == null"); 209 } 210 return Method.getAnnotation(declaringClass, slot, annotationType); 211 } 212 213 @Override public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) { 214 if (annotationType == null) { 215 throw new NullPointerException("annotationType == null"); 216 } 217 return Method.isAnnotationPresent(declaringClass, slot, annotationType); 218 } 219 220 /** 221 * Returns an array of arrays that represent the annotations of the formal 222 * parameters of this constructor. If there are no parameters on this 223 * constructor, then an empty array is returned. If there are no annotations 224 * set, then an array of empty arrays is returned. 225 * 226 * @return an array of arrays of {@code Annotation} instances 227 */ 228 public Annotation[][] getParameterAnnotations() { 229 Annotation[][] parameterAnnotations 230 = Method.getParameterAnnotations(declaringClass, slot); 231 if (parameterAnnotations.length == 0) { 232 return Method.noAnnotations(parameterTypes.length); 233 } 234 return parameterAnnotations; 235 } 236 237 /** 238 * Indicates whether or not this constructor takes a variable number of 239 * arguments. 240 * 241 * @return {@code true} if a vararg is declare, otherwise 242 * {@code false} 243 */ 244 public boolean isVarArgs() { 245 int mods = Method.getMethodModifiers(declaringClass, slot); 246 return (mods & Modifier.VARARGS) != 0; 247 } 248 249 /** 250 * Indicates whether or not this constructor is synthetic (artificially 251 * introduced by the compiler). 252 * 253 * @return {@code true} if this constructor is synthetic, {@code false} 254 * otherwise 255 */ 256 public boolean isSynthetic() { 257 int mods = Method.getMethodModifiers(declaringClass, slot); 258 return (mods & Modifier.SYNTHETIC) != 0; 259 } 260 261 /** 262 * Indicates whether or not the specified {@code object} is equal to this 263 * constructor. To be equal, the specified object must be an instance 264 * of {@code Constructor} with the same declaring class and parameter types 265 * as this constructor. 266 * 267 * @param object 268 * the object to compare 269 * 270 * @return {@code true} if the specified object is equal to this 271 * constructor, {@code false} otherwise 272 * 273 * @see #hashCode 274 */ 275 @Override 276 public boolean equals(Object object) { 277 return object instanceof Constructor && toString().equals(object.toString()); 278 } 279 280 /** 281 * Returns the class that declares this constructor. 282 * 283 * @return the declaring class 284 */ 285 public Class<T> getDeclaringClass() { 286 return declaringClass; 287 } 288 289 /** 290 * Returns the exception types as an array of {@code Class} instances. If 291 * this constructor has no declared exceptions, an empty array will be 292 * returned. 293 * 294 * @return the declared exception classes 295 */ 296 public Class<?>[] getExceptionTypes() { 297 if (exceptionTypes == null) { 298 return EmptyArray.CLASS; 299 } 300 return exceptionTypes.clone(); 301 } 302 303 /** 304 * Returns the modifiers for this constructor. The {@link Modifier} class 305 * should be used to decode the result. 306 * 307 * @return the modifiers for this constructor 308 * 309 * @see Modifier 310 */ 311 public int getModifiers() { 312 return Method.getMethodModifiers(declaringClass, slot); 313 } 314 315 /** 316 * Returns the name of this constructor. 317 * 318 * @return the name of this constructor 319 */ 320 public String getName() { 321 return declaringClass.getName(); 322 } 323 324 /** 325 * Returns an array of the {@code Class} objects associated with the 326 * parameter types of this constructor. If the constructor was declared with 327 * no parameters, an empty array will be returned. 328 * 329 * @return the parameter types 330 */ 331 public Class<?>[] getParameterTypes() { 332 return parameterTypes.clone(); 333 } 334 335 /** 336 * Returns the constructor's signature in non-printable form. This is called 337 * (only) from IO native code and needed for deriving the serialVersionUID 338 * of the class 339 * 340 * @return the constructor's signature 341 */ 342 @SuppressWarnings("unused") 343 private String getSignature() { 344 StringBuilder result = new StringBuilder(); 345 346 result.append('('); 347 for (int i = 0; i < parameterTypes.length; i++) { 348 result.append(getSignature(parameterTypes[i])); 349 } 350 result.append(")V"); 351 352 return result.toString(); 353 } 354 355 /** 356 * Returns an integer hash code for this constructor. Constructors which are 357 * equal return the same value for this method. The hash code for a 358 * Constructor is the hash code of the name of the declaring class. 359 * 360 * @return the hash code 361 * 362 * @see #equals 363 */ 364 @Override 365 public int hashCode() { 366 return declaringClass.getName().hashCode(); 367 } 368 369 /** 370 * Returns a new instance of the declaring class, initialized by dynamically 371 * invoking the constructor represented by this {@code Constructor} object. 372 * This reproduces the effect of {@code new declaringClass(arg1, arg2, ... , 373 * argN)} This method performs the following: 374 * <ul> 375 * <li>A new instance of the declaring class is created. If the declaring 376 * class cannot be instantiated (i.e. abstract class, an interface, an array 377 * type, or a primitive type) then an InstantiationException is thrown.</li> 378 * <li>If this Constructor object is enforcing access control (see 379 * {@link AccessibleObject}) and this constructor is not accessible from the 380 * current context, an IllegalAccessException is thrown.</li> 381 * <li>If the number of arguments passed and the number of parameters do not 382 * match, an IllegalArgumentException is thrown.</li> 383 * <li>For each argument passed: 384 * <ul> 385 * <li>If the corresponding parameter type is a primitive type, the argument 386 * is unboxed. If the unboxing fails, an IllegalArgumentException is 387 * thrown.</li> 388 * <li>If the resulting argument cannot be converted to the parameter type 389 * via a widening conversion, an IllegalArgumentException is thrown.</li> 390 * </ul> 391 * <li>The constructor represented by this {@code Constructor} object is 392 * then invoked. If an exception is thrown during the invocation, it is 393 * caught and wrapped in an InvocationTargetException. This exception is 394 * then thrown. If the invocation completes normally, the newly initialized 395 * object is returned. 396 * </ul> 397 * 398 * @param args 399 * the arguments to the constructor 400 * 401 * @return the new, initialized, object 402 * 403 * @exception InstantiationException 404 * if the class cannot be instantiated 405 * @exception IllegalAccessException 406 * if this constructor is not accessible 407 * @exception IllegalArgumentException 408 * if an incorrect number of arguments are passed, or an 409 * argument could not be converted by a widening conversion 410 * @exception InvocationTargetException 411 * if an exception was thrown by the invoked constructor 412 * 413 * @see AccessibleObject 414 */ 415 public T newInstance(Object... args) throws InstantiationException, IllegalAccessException, 416 IllegalArgumentException, InvocationTargetException { 417 return constructNative (args, declaringClass, parameterTypes, slot, flag); 418 } 419 420 private native T constructNative(Object[] args, Class<T> declaringClass, 421 Class<?>[] parameterTypes, int slot, 422 boolean noAccessCheck) throws InstantiationException, IllegalAccessException, 423 InvocationTargetException; 424 425 /** 426 * Returns a string containing a concise, human-readable description of this 427 * constructor. The format of the string is: 428 * 429 * <ol> 430 * <li>modifiers (if any) 431 * <li>declaring class name 432 * <li>'(' 433 * <li>parameter types, separated by ',' (if any) 434 * <li>')' 435 * <li>'throws' plus exception types, separated by ',' (if any) 436 * </ol> 437 * 438 * For example: 439 * {@code public String(byte[],String) throws UnsupportedEncodingException} 440 * 441 * @return a printable representation for this constructor 442 */ 443 @Override 444 public String toString() { 445 StringBuilder result = new StringBuilder(Modifier.toString(getModifiers())); 446 447 if (result.length() != 0) 448 result.append(' '); 449 result.append(declaringClass.getName()); 450 result.append("("); 451 result.append(toString(parameterTypes)); 452 result.append(")"); 453 if (exceptionTypes != null && exceptionTypes.length != 0) { 454 result.append(" throws "); 455 result.append(toString(exceptionTypes)); 456 } 457 458 return result.toString(); 459 } 460} 461