Constructor.java revision 98a7a76fe5c0dd5ff949b38da809368681169205
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 dalvik.system.VMStack; 36 37import java.lang.annotation.Annotation; 38 39import org.apache.harmony.kernel.vm.StringUtils; 40import org.apache.harmony.luni.lang.reflect.GenericSignatureParser; 41import org.apache.harmony.luni.lang.reflect.ListOfTypes; 42import org.apache.harmony.luni.lang.reflect.Types; 43 44/** 45 * This class represents a constructor. Information about the constructor can be 46 * accessed, and the constructor can be invoked dynamically. 47 * 48 * @param <T> the class that declares this constructor 49 */ 50public final class Constructor<T> extends AccessibleObject implements GenericDeclaration, 51 Member { 52 53 Class<T> declaringClass; 54 55 Class<?>[] parameterTypes; 56 57 Class<?>[] exceptionTypes; 58 59 ListOfTypes genericExceptionTypes; 60 ListOfTypes genericParameterTypes; 61 TypeVariable<Constructor<T>>[] formalTypeParameters; 62 private volatile boolean genericTypesAreInitialized = false; 63 64 private synchronized void initGenericTypes() { 65 if (!genericTypesAreInitialized) { 66 String signatureAttribute = getSignatureAttribute(); 67 GenericSignatureParser parser = new GenericSignatureParser( 68 VMStack.getCallingClassLoader2()); 69 parser.parseForConstructor(this, signatureAttribute, exceptionTypes); 70 formalTypeParameters = parser.formalTypeParameters; 71 genericParameterTypes = parser.parameterTypes; 72 genericExceptionTypes = parser.exceptionTypes; 73 genericTypesAreInitialized = true; 74 } 75 } 76 77 int slot; 78 79 /** 80 * Prevent this class from being instantiated. 81 */ 82 private Constructor(){ 83 //do nothing 84 } 85 86 /** 87 * Creates an instance of the class. Only called from native code, thus 88 * private. 89 * 90 * @param declaringClass 91 * the class this constructor object belongs to 92 * @param ptypes 93 * the parameter types of the constructor 94 * @param extypes 95 * the exception types of the constructor 96 * @param slot 97 * the slot of the constructor inside the VM class structure 98 */ 99 private Constructor (Class<T> declaringClass, Class<?>[] ptypes, Class<?>[] extypes, int slot){ 100 this.declaringClass = declaringClass; 101 this.parameterTypes = ptypes; 102 this.exceptionTypes = extypes; // may be null 103 this.slot = slot; 104 } 105 106 @Override /*package*/ String getSignatureAttribute() { 107 Object[] annotation = getSignatureAnnotation(declaringClass, slot); 108 109 if (annotation == null) { 110 return null; 111 } 112 113 return StringUtils.combineStrings(annotation); 114 } 115 116 /** 117 * Get the Signature annotation for this constructor. Returns null if not 118 * found. 119 */ 120 native private Object[] getSignatureAnnotation(Class declaringClass, 121 int slot); 122 123 public TypeVariable<Constructor<T>>[] getTypeParameters() { 124 initGenericTypes(); 125 return formalTypeParameters.clone(); 126 } 127 128 /** 129 * Returns the string representation of the constructor's declaration, 130 * including the type parameters. 131 * 132 * @return the string representation of the constructor's declaration 133 */ 134 public String toGenericString() { 135 StringBuilder sb = new StringBuilder(80); 136 initGenericTypes(); 137 // append modifiers if any 138 int modifier = getModifiers(); 139 if (modifier != 0) { 140 sb.append(Modifier.toString(modifier & ~Modifier.VARARGS)).append(' '); 141 } 142 // append type parameters 143 if (formalTypeParameters != null && formalTypeParameters.length > 0) { 144 sb.append('<'); 145 for (int i = 0; i < formalTypeParameters.length; i++) { 146 appendGenericType(sb, formalTypeParameters[i]); 147 if (i < formalTypeParameters.length - 1) { 148 sb.append(", "); 149 } 150 } 151 sb.append("> "); 152 } 153 // append constructor name 154 appendArrayType(sb, getDeclaringClass()); 155 // append parameters 156 sb.append('('); 157 appendArrayGenericType(sb, 158 Types.getClonedTypeArray(genericParameterTypes)); 159 sb.append(')'); 160 // append exceptions if any 161 Type[] genericExceptionTypeArray = 162 Types.getClonedTypeArray(genericExceptionTypes); 163 if (genericExceptionTypeArray.length > 0) { 164 sb.append(" throws "); 165 appendArrayGenericType(sb, genericExceptionTypeArray); 166 } 167 return sb.toString(); 168 } 169 170 /** 171 * Returns the generic parameter types as an array of {@code Type} 172 * instances, in declaration order. If this constructor has no generic 173 * parameters, an empty array is returned. 174 * 175 * @return the parameter types 176 * 177 * @throws GenericSignatureFormatError 178 * if the generic constructor signature is invalid 179 * @throws TypeNotPresentException 180 * if any parameter type points to a missing type 181 * @throws MalformedParameterizedTypeException 182 * if any parameter type points to a type that cannot be 183 * instantiated for some reason 184 */ 185 public Type[] getGenericParameterTypes() { 186 initGenericTypes(); 187 return Types.getClonedTypeArray(genericParameterTypes); 188 } 189 190 /** 191 * Returns the exception types as an array of {@code Type} instances. If 192 * this constructor has no declared exceptions, an empty array will be 193 * returned. 194 * 195 * @return an array of generic exception types 196 * 197 * @throws GenericSignatureFormatError 198 * if the generic constructor signature is invalid 199 * @throws TypeNotPresentException 200 * if any exception type points to a missing type 201 * @throws MalformedParameterizedTypeException 202 * if any exception type points to a type that cannot be 203 * instantiated for some reason 204 */ 205 public Type[] getGenericExceptionTypes() { 206 initGenericTypes(); 207 return Types.getClonedTypeArray(genericExceptionTypes); 208 } 209 210 @Override 211 public Annotation[] getDeclaredAnnotations() { 212 return getDeclaredAnnotations(declaringClass, slot); 213 } 214 native private Annotation[] getDeclaredAnnotations(Class declaringClass, 215 int slot); 216 217 /** 218 * Returns an array of arrays that represent the annotations of the formal 219 * parameters of this constructor. If there are no parameters on this 220 * constructor, then an empty array is returned. If there are no annotations 221 * set, then an array of empty arrays is returned. 222 * 223 * @return an array of arrays of {@code Annotation} instances 224 */ 225 public Annotation[][] getParameterAnnotations() { 226 Annotation[][] parameterAnnotations 227 = getParameterAnnotations(declaringClass, slot); 228 if (parameterAnnotations.length == 0) { 229 return Method.noAnnotations(parameterTypes.length); 230 } 231 return parameterAnnotations; 232 } 233 native private Annotation[][] getParameterAnnotations(Class declaringClass, 234 int slot); 235 236 /** 237 * Indicates whether or not this constructor takes a variable number of 238 * arguments. 239 * 240 * @return {@code true} if a vararg is declare, otherwise 241 * {@code false} 242 */ 243 public boolean isVarArgs() { 244 int mods = getConstructorModifiers(declaringClass, slot); 245 return (mods & Modifier.VARARGS) != 0; 246 } 247 248 /** 249 * Indicates whether or not this constructor is synthetic (artificially 250 * introduced by the compiler). 251 * 252 * @return {@code true} if this constructor is synthetic, {@code false} 253 * otherwise 254 */ 255 public boolean isSynthetic() { 256 int mods = getConstructorModifiers(declaringClass, slot); 257 return (mods & Modifier.SYNTHETIC) != 0; 258 } 259 260 /** 261 * Indicates whether or not the specified {@code object} is equal to this 262 * constructor. To be equal, the specified object must be an instance 263 * of {@code Constructor} with the same declaring class and parameter types 264 * as this constructor. 265 * 266 * @param object 267 * the object to compare 268 * 269 * @return {@code true} if the specified object is equal to this 270 * constructor, {@code false} otherwise 271 * 272 * @see #hashCode 273 */ 274 @Override 275 public boolean equals(Object object) { 276 return object instanceof Constructor && toString().equals(object.toString()); 277 } 278 279 /** 280 * Returns the class that declares this constructor. 281 * 282 * @return the declaring class 283 */ 284 public Class<T> getDeclaringClass() { 285 return declaringClass; 286 } 287 288 /** 289 * Returns the exception types as an array of {@code Class} instances. If 290 * this constructor has no declared exceptions, an empty array will be 291 * returned. 292 * 293 * @return the declared exception classes 294 */ 295 public Class<?>[] getExceptionTypes() { 296 if (exceptionTypes == null) 297 return new Class[0]; 298 return exceptionTypes.clone(); 299 } 300 301 /** 302 * Returns the modifiers for this constructor. The {@link Modifier} class 303 * should be used to decode the result. 304 * 305 * @return the modifiers for this constructor 306 * 307 * @see Modifier 308 */ 309 public int getModifiers() { 310 return getConstructorModifiers(declaringClass, slot); 311 } 312 313 private native int getConstructorModifiers(Class<T> declaringClass, int slot); 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 unwrapped. If the unwrapping 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