/* * 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) 2006-2007 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; import com.android.dex.Dex; import dalvik.system.VMStack; import java.io.InputStream; import java.io.Serializable; import java.lang.annotation.Annotation; import java.lang.reflect.AccessibleObject; import java.lang.reflect.AnnotatedElement; import java.lang.reflect.ArtField; import java.lang.reflect.ArtMethod; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.GenericDeclaration; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Member; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; import java.net.URL; import java.security.ProtectionDomain; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import libcore.reflect.AnnotationAccess; import libcore.reflect.GenericSignatureParser; import libcore.reflect.InternalNames; import libcore.reflect.Types; import libcore.util.BasicLruCache; import libcore.util.CollectionUtils; import libcore.util.EmptyArray; import libcore.util.SneakyThrow; /** * The in-memory representation of a Java class. This representation serves as * the starting point for querying class-related information, a process usually * called "reflection". There are basically three types of {@code Class} * instances: those representing real classes and interfaces, those representing * primitive types, and those representing array classes. * *
* These represent an ordinary class or interface as found in the class * hierarchy. The name associated with these {@code Class} instances is simply * the fully qualified class name of the class or interface that it represents. * In addition to this human-readable name, each class is also associated by a * so-called descriptor, which is the letter "L", followed by the * class name and a semicolon (";"). The descriptor is what the runtime system * uses internally for identifying the class (for example in a DEX file). *
** These represent the standard Java primitive types and hence share their * names (for example "int" for the {@code int} primitive type). Although it is * not possible to create new instances based on these {@code Class} instances, * they are still useful for providing reflection information, and as the * component type of array classes. There is one {@code Class} instance for each * primitive type, and their descriptors are: *
**
* These represent the classes of Java arrays. There is one such {@code Class} * instance per combination of array leaf component type and arity (number of * dimensions). In this case, the name associated with the {@code Class} * consists of one or more left square brackets (one per dimension in the array) * followed by the descriptor of the class representing the leaf component type, * which can be either an object type or a primitive type. The descriptor of a * {@code Class} representing an array type is the same as its name. Examples * of array class descriptors are: *
*If the class has not yet been loaded, it is loaded and initialized * first. This is done through either the class loader of the calling class * or one of its parent class loaders. It is possible that a static initializer is run as * a result of this call. * * @throws ClassNotFoundException * if the requested class cannot be found. * @throws LinkageError * if an error occurs during linkage * @throws ExceptionInInitializerError * if an exception occurs during static initialization of a * class. */ public static Class> forName(String className) throws ClassNotFoundException { return forName(className, true, VMStack.getCallingClassLoader()); } /** * Returns a {@code Class} object which represents the class with * the given name. The name should be the name of a non-primitive * class, as described in the {@link Class class definition}. * Primitive types can not be found using this method; use {@code * int.class} or {@code Integer.TYPE} instead. * *
If the class has not yet been loaded, it is loaded first, using the given class loader.
* If the class has not yet been initialized and {@code shouldInitialize} is true,
* the class will be initialized.
*
* @throws ClassNotFoundException
* if the requested class cannot be found.
* @throws LinkageError
* if an error occurs during linkage
* @throws ExceptionInInitializerError
* if an exception occurs during static initialization of a
* class.
*/
public static Class> forName(String className, boolean shouldInitialize,
ClassLoader classLoader) throws ClassNotFoundException {
if (classLoader == null) {
classLoader = ClassLoader.getSystemClassLoader();
}
// Catch an Exception thrown by the underlying native code. It wraps
// up everything inside a ClassNotFoundException, even if e.g. an
// Error occurred during initialization. This as a workaround for
// an ExceptionInInitializerError that's also wrapped. It is actually
// expected to be thrown. Maybe the same goes for other errors.
// Not wrapping up all the errors will break android though.
Class> result;
try {
result = classForName(className, shouldInitialize, classLoader);
} catch (ClassNotFoundException e) {
Throwable cause = e.getCause();
if (cause instanceof LinkageError) {
throw (LinkageError) cause;
}
throw e;
}
return result;
}
static native Class> classForName(String className, boolean shouldInitialize,
ClassLoader classLoader) throws ClassNotFoundException;
/**
* Returns an array containing {@code Class} objects for all
* public classes, interfaces, enums and annotations that are
* members of this class and its superclasses. This does not
* include classes of implemented interfaces. If there are no
* such class members or if this object represents a primitive
* type then an array of length 0 is returned.
*/
public Class>[] getClasses() {
List If there are no public methods or if this {@code Class} represents a
* primitive type or {@code void} then an empty array is returned.
*
* @see #getDeclaredMethods()
*/
public Method[] getMethods() {
List This is a hack that exploits an implementation detail of all Java
* language compilers: generated names always contain "$". As it is possible
* for a top level class to be named with a "$", a false result does
* not indicate that this isn't a top-level class.
*/
private boolean classNameImpliesTopLevel() {
return !getName().contains("$");
}
/**
* Returns the {@code enum} constants associated with this {@code Class}.
* Returns {@code null} if this {@code Class} does not represent an {@code
* enum} type.
*/
@SuppressWarnings("unchecked") // we only cast after confirming that this class is an enum
public T[] getEnumConstants() {
if (!isEnum()) {
return null;
}
return (T[]) Enum.getSharedConstants((Class) this).clone();
}
/**
* Returns a {@code Field} object which represents the public field with the
* given name. This method first searches the class C represented by
* this {@code Class}, then the interfaces implemented by C and finally the
* superclasses of C.
*
* @throws NoSuchFieldException
* if the field cannot be found.
* @see #getDeclaredField(String)
*/
public Field getField(String name) throws NoSuchFieldException {
if (name == null) {
throw new NullPointerException("name == null");
}
Field result = getPublicFieldRecursive(name);
if (result == null) {
throw new NoSuchFieldException(name);
} else {
result.getType(); // Throw NoClassDefFoundError if type cannot be resolved.
}
return result;
}
private Field getPublicFieldRecursive(String name) {
// search superclasses
for (Class> c = this; c != null; c = c.superClass) {
Field result = c.getDeclaredFieldInternal(name);
if (result != null && (result.getModifiers() & Modifier.PUBLIC) != 0) {
return result;
}
}
// search iftable which has a flattened and uniqued list of interfaces
if (ifTable != null) {
for (int i = 0; i < ifTable.length; i += 2) {
Class> ifc = (Class>) ifTable[i];
Field result = ifc.getPublicFieldRecursive(name);
if (result != null && (result.getModifiers() & Modifier.PUBLIC) != 0) {
return result;
}
}
}
return null;
}
/**
* Returns an array containing {@code Field} objects for all public fields
* for the class C represented by this {@code Class}. Fields may be declared
* in C, the interfaces it implements or in the superclasses of C. The
* elements in the returned array are in no particular order.
*
* If there are no public fields or if this class represents an array class,
* a primitive type or {@code void} then an empty array is returned.
*
* @see #getDeclaredFields()
*/
public Field[] getFields() {
List This method only returns directly-implemented interfaces, and does not
* include interfaces implemented by superclasses or superinterfaces of any
* implemented interfaces.
*/
public Class>[] getInterfaces() {
if (isArray()) {
return new Class>[] { Cloneable.class, Serializable.class };
} else if (isProxy()) {
return getProxyInterfaces();
}
Dex dex = getDex();
if (dex == null) {
return EmptyArray.CLASS;
}
short[] interfaces = dex.interfaceTypeIndicesFromClassDefIndex(dexClassDefIndex);
Class>[] result = new Class>[interfaces.length];
for (int i = 0; i < interfaces.length; i++) {
result[i] = getDexCacheType(dex, interfaces[i]);
}
return result;
}
// Returns the interfaces that this proxy class directly implements.
private native Class>[] getProxyInterfaces();
/**
* Returns an integer that represents the modifiers of the class represented
* by this {@code Class}. The returned value is a combination of bits
* defined by constants in the {@link Modifier} class.
*/
public int getModifiers() {
// Array classes inherit modifiers from their component types, but in the case of arrays
// of an inner class, the class file may contain "fake" access flags because it's not valid
// for a top-level class to private, say. The real access flags are stored in the InnerClass
// attribute, so we need to make sure we drill down to the inner class: the accessFlags
// field is not the value we want to return, and the synthesized array class does not itself
// have an InnerClass attribute. https://code.google.com/p/android/issues/detail?id=56267
if (isArray()) {
int componentModifiers = getComponentType().getModifiers();
if ((componentModifiers & Modifier.INTERFACE) != 0) {
componentModifiers &= ~(Modifier.INTERFACE | Modifier.STATIC);
}
return Modifier.ABSTRACT | Modifier.FINAL | componentModifiers;
}
int JAVA_FLAGS_MASK = 0xffff;
int modifiers = AnnotationAccess.getInnerClassFlags(this, accessFlags & JAVA_FLAGS_MASK);
return modifiers & JAVA_FLAGS_MASK;
}
/**
* Returns the name of the class represented by this {@code Class}. For a
* description of the format which is used, see the class definition of
* {@link Class}.
*/
public String getName() {
String result = name;
return (result == null) ? (name = getNameNative()) : result;
}
private native String getNameNative();
/**
* Returns the simple name of the class represented by this {@code Class} as
* defined in the source code. If there is no name (that is, the class is
* anonymous) then an empty string is returned. If the receiver is an array
* then the name of the underlying type with square braces appended (for
* example {@code "Integer[]"}) is returned.
*
* @return the simple name of the class represented by this {@code Class}.
*/
public String getSimpleName() {
if (isArray()) {
return getComponentType().getSimpleName() + "[]";
}
if (isAnonymousClass()) {
return "";
}
if (isMemberClass() || isLocalClass()) {
return getInnerClassName();
}
String name = getName();
int dot = name.lastIndexOf('.');
if (dot != -1) {
return name.substring(dot + 1);
}
return name;
}
/**
* Returns the simple name of a member or local class, or null otherwise.
*/
private String getInnerClassName() {
return AnnotationAccess.getInnerClassName(this);
}
/**
* Returns null.
*/
public ProtectionDomain getProtectionDomain() {
return null;
}
/**
* Returns the URL of the given resource, or null if the resource is not found.
* The mapping between the resource name and the URL is managed by the class' class loader.
*
* @see ClassLoader
*/
public URL getResource(String resourceName) {
// Get absolute resource name, but without the leading slash
if (resourceName.startsWith("/")) {
resourceName = resourceName.substring(1);
} else {
String pkg = getName();
int dot = pkg.lastIndexOf('.');
if (dot != -1) {
pkg = pkg.substring(0, dot).replace('.', '/');
} else {
pkg = "";
}
resourceName = pkg + "/" + resourceName;
}
// Delegate to proper class loader
ClassLoader loader = getClassLoader();
if (loader != null) {
return loader.getResource(resourceName);
} else {
return ClassLoader.getSystemResource(resourceName);
}
}
/**
* Returns a read-only stream for the contents of the given resource, or null if the resource
* is not found.
* The mapping between the resource name and the stream is managed by the class' class loader.
*
* @see ClassLoader
*/
public InputStream getResourceAsStream(String resourceName) {
// Get absolute resource name, but without the leading slash
if (resourceName.startsWith("/")) {
resourceName = resourceName.substring(1);
} else {
String pkg = getName();
int dot = pkg.lastIndexOf('.');
if (dot != -1) {
pkg = pkg.substring(0, dot).replace('.', '/');
} else {
pkg = "";
}
resourceName = pkg + "/" + resourceName;
}
// Delegate to proper class loader
ClassLoader loader = getClassLoader();
if (loader != null) {
return loader.getResourceAsStream(resourceName);
} else {
return ClassLoader.getSystemResourceAsStream(resourceName);
}
}
/**
* Returns null. (On Android, a {@code ClassLoader} can load classes from multiple dex files.
* All classes from any given dex file will have the same signers, but different dex
* files may have different signers. This does not fit well with the original
* {@code ClassLoader}-based model of {@code getSigners}.)
*/
public Object[] getSigners() {
// See http://code.google.com/p/android/issues/detail?id=1766.
return null;
}
/**
* Returns the {@code Class} object which represents the superclass of the
* class represented by this {@code Class}. If this {@code Class} represents
* the {@code Object} class, a primitive type, an interface or void then the
* method returns {@code null}. If this {@code Class} represents an array
* class then the {@code Object} class is returned.
*/
public Class super T> getSuperclass() {
// For interfaces superClass is Object (which agrees with the JNI spec)
// but not with the expected behavior here.
if (isInterface()) {
return null;
} else {
return superClass;
}
}
/**
* Returns an array containing {@code TypeVariable} objects for type
* variables declared by the generic class represented by this {@code
* Class}. Returns an empty array if the class is not generic.
*/
@SuppressWarnings("unchecked")
@Override public synchronized TypeVariable