/*
* 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);
}
}