• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
33 package java.lang.reflect;
34 
35 import java.lang.annotation.Annotation;
36 import libcore.util.EmptyArray;
37 import org.apache.harmony.kernel.vm.StringUtils;
38 import org.apache.harmony.luni.lang.reflect.GenericSignatureParser;
39 import org.apache.harmony.luni.lang.reflect.ListOfTypes;
40 import 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  */
48 public 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 
initGenericTypes()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      */
Constructor()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      */
Constructor(Class<T> declaringClass, Class<?>[] ptypes, Class<?>[] extypes, int slot)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 
getSignatureAttribute()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 
getTypeParameters()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      */
toGenericString()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      */
getGenericParameterTypes()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      */
getGenericExceptionTypes()196     public Type[] getGenericExceptionTypes() {
197         initGenericTypes();
198         return Types.getClonedTypeArray(genericExceptionTypes);
199     }
200 
201     @Override
getDeclaredAnnotations()202     public Annotation[] getDeclaredAnnotations() {
203         return Method.getDeclaredAnnotations(declaringClass, slot);
204     }
205 
getAnnotation(Class<A> annotationType)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 
isAnnotationPresent(Class<? extends Annotation> annotationType)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      */
getParameterAnnotations()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      */
isVarArgs()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      */
isSynthetic()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
equals(Object object)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      */
getDeclaringClass()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      */
getExceptionTypes()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      */
getModifiers()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      */
getName()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      */
getParameterTypes()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")
getSignature()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
hashCode()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      */
newInstance(Object... args)415     public T newInstance(Object... args) throws InstantiationException, IllegalAccessException,
416             IllegalArgumentException, InvocationTargetException {
417         return constructNative (args, declaringClass, parameterTypes, slot, flag);
418     }
419 
constructNative(Object[] args, Class<T> declaringClass, Class<?>[] parameterTypes, int slot, boolean noAccessCheck)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
toString()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