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