/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * Copyright (C) 2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package java.lang.reflect; import com.android.dex.Dex; import java.lang.annotation.Annotation; import java.util.Comparator; import java.util.List; import libcore.reflect.AnnotationAccess; import libcore.reflect.Types; /** * This class represents a constructor. Information about the constructor can be * accessed, and the constructor can be invoked dynamically. * * @param <T> the class that declares this constructor */ public final class Constructor<T> extends AbstractMethod implements GenericDeclaration, Member { private static final Comparator<Method> ORDER_BY_SIGNATURE = null; // Unused; must match Method. private Constructor() { } public Annotation[] getAnnotations() { return super.getAnnotations(); } /** * Returns the modifiers for this constructor. The {@link Modifier} class * should be used to decode the result. */ @Override public int getModifiers() { return super.getModifiers(); } /** * Returns true if this constructor takes a variable number of arguments. */ public boolean isVarArgs() { return super.isVarArgs(); } /** * Returns true if this constructor is synthetic (artificially introduced by the compiler). */ @Override public boolean isSynthetic() { return super.isSynthetic(); } /** * Returns the name of this constructor. */ @Override public String getName() { return getDeclaringClass().getName(); } /** * Returns the class that declares this constructor. */ @Override public Class<T> getDeclaringClass() { return (Class<T>) super.getDeclaringClass(); } /** * Returns the exception types as an array of {@code Class} instances. If * this constructor has no declared exceptions, an empty array will be * returned. */ public Class<?>[] getExceptionTypes() { // TODO: use dex cache to speed looking up class return AnnotationAccess.getExceptions(this); } /** * Returns an array of the {@code Class} objects associated with the * parameter types of this constructor. If the constructor was declared with * no parameters, an empty array will be returned. */ @Override public Class<?>[] getParameterTypes() { return super.getParameterTypes(); } /** * {@inheritDoc} * * <p>Equivalent to {@code getDeclaringClass().getName().hashCode()}. */ @Override public int hashCode() { return getDeclaringClass().getName().hashCode(); } /** * Returns true if {@code other} has the same declaring class and parameters * as this constructor. */ @Override public boolean equals(Object other) { return super.equals(other); } @Override public TypeVariable<Constructor<T>>[] getTypeParameters() { GenericInfo info = getMethodOrConstructorGenericInfo(); return (TypeVariable<Constructor<T>>[]) info.formalTypeParameters.clone(); } /** * Returns the string representation of the constructor's declaration, * including the type parameters. * * @return the string representation of the constructor's declaration */ public String toGenericString() { return super.toGenericString(); } /** * Returns the generic parameter types as an array of {@code Type} * instances, in declaration order. If this constructor has no generic * parameters, an empty array is returned. * * @return the parameter types * * @throws GenericSignatureFormatError * if the generic constructor signature is invalid * @throws TypeNotPresentException * if any parameter type points to a missing type * @throws MalformedParameterizedTypeException * if any parameter type points to a type that cannot be * instantiated for some reason */ public Type[] getGenericParameterTypes() { return super.getGenericParameterTypes(); } /** * Returns the exception types as an array of {@code Type} instances. If * this constructor has no declared exceptions, an empty array will be * returned. * * @return an array of generic exception types * * @throws GenericSignatureFormatError * if the generic constructor signature is invalid * @throws TypeNotPresentException * if any exception type points to a missing type * @throws MalformedParameterizedTypeException * if any exception type points to a type that cannot be * instantiated for some reason */ public Type[] getGenericExceptionTypes() { return super.getGenericExceptionTypes(); } @Override public Annotation[] getDeclaredAnnotations() { List<Annotation> result = AnnotationAccess.getDeclaredAnnotations(this); return result.toArray(new Annotation[result.size()]); } @Override public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) { if (annotationType == null) { throw new NullPointerException("annotationType == null"); } return AnnotationAccess.isDeclaredAnnotationPresent(this, annotationType); } @Override public <A extends Annotation> A getAnnotation(Class<A> annotationType) { if (annotationType == null) { throw new NullPointerException("annotationType == null"); } return AnnotationAccess.getDeclaredAnnotation(this, annotationType); } /** * Returns an array of arrays that represent the annotations of the formal * parameters of this constructor. If there are no parameters on this * constructor, then an empty array is returned. If there are no annotations * set, then an array of empty arrays is returned. * * @return an array of arrays of {@code Annotation} instances */ public Annotation[][] getParameterAnnotations() { return AnnotationAccess.getParameterAnnotations( declaringClassOfOverriddenMethod, dexMethodIndex); } /** * Returns the constructor's signature in non-printable form. This is called * (only) from IO native code and needed for deriving the serialVersionUID * of the class * * @return the constructor's signature */ @SuppressWarnings("unused") String getSignature() { StringBuilder result = new StringBuilder(); result.append('('); Class<?>[] parameterTypes = getParameterTypes(); for (Class<?> parameterType : parameterTypes) { result.append(Types.getSignature(parameterType)); } result.append(")V"); return result.toString(); } /** * Returns a new instance of the declaring class, initialized by dynamically * invoking the constructor represented by this {@code Constructor} object. * This reproduces the effect of {@code new declaringClass(arg1, arg2, ... , * argN)} This method performs the following: * <ul> * <li>A new instance of the declaring class is created. If the declaring * class cannot be instantiated (i.e. abstract class, an interface, an array * type, or a primitive type) then an InstantiationException is thrown.</li> * <li>If this Constructor object is enforcing access control (see * {@link AccessibleObject}) and this constructor is not accessible from the * current context, an IllegalAccessException is thrown.</li> * <li>If the number of arguments passed and the number of parameters do not * match, an IllegalArgumentException is thrown.</li> * <li>For each argument passed: * <ul> * <li>If the corresponding parameter type is a primitive type, the argument * is unboxed. If the unboxing fails, an IllegalArgumentException is * thrown.</li> * <li>If the resulting argument cannot be converted to the parameter type * via a widening conversion, an IllegalArgumentException is thrown.</li> * </ul> * <li>The constructor represented by this {@code Constructor} object is * then invoked. If an exception is thrown during the invocation, it is * caught and wrapped in an InvocationTargetException. This exception is * then thrown. If the invocation completes normally, the newly initialized * object is returned. * </ul> * * @param args * the arguments to the constructor * * @return the new, initialized, object * * @exception InstantiationException * if the class cannot be instantiated * @exception IllegalAccessException * if this constructor is not accessible * @exception IllegalArgumentException * if an incorrect number of arguments are passed, or an * argument could not be converted by a widening conversion * @exception InvocationTargetException * if an exception was thrown by the invoked constructor * * @see AccessibleObject */ public native T newInstance(Object... args) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException; /** * Returns a string containing a concise, human-readable description of this * constructor. The format of the string is: * * <ol> * <li>modifiers (if any) * <li>declaring class name * <li>'(' * <li>parameter types, separated by ',' (if any) * <li>')' * <li>'throws' plus exception types, separated by ',' (if any) * </ol> * * For example: * {@code public String(byte[],String) throws UnsupportedEncodingException} * * @return a printable representation for this constructor */ @Override public String toString() { StringBuilder result = new StringBuilder(Modifier.toString(getModifiers())); if (result.length() != 0) { result.append(' '); } result.append(getDeclaringClass().getName()); result.append("("); Class<?>[] parameterTypes = getParameterTypes(); result.append(Types.toString(parameterTypes)); result.append(")"); Class<?>[] exceptionTypes = getExceptionTypes(); if (exceptionTypes.length > 0) { result.append(" throws "); result.append(Types.toString(exceptionTypes)); } return result.toString(); } /** * Attempts to set the accessible flag. Setting this to true prevents {@code * IllegalAccessExceptions}. */ public void setAccessible(boolean flag) { Class<?> declaringClass = getDeclaringClass(); if (declaringClass == Class.class) { throw new SecurityException("Can't make class constructor accessible"); } else if (declaringClass == Field.class) { throw new SecurityException("Can't make field constructor accessible"); } else if (declaringClass == Method.class) { throw new SecurityException("Can't make method constructor accessible"); } super.setAccessible(flag); } }