blob: c66b01a800123916d345b3207bdded5382ca5042 [file] [log] [blame]
/*
* 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.
*
* <h4>Class instances representing object types (classes or interfaces)</h4>
* <p>
* 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 <em>descriptor</em>, 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).
* </p>
* <h4>Classes representing primitive types</h4>
* <p>
* 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:
* </p>
* <ul>
* <li>{@code B} representing the {@code byte} primitive type</li>
* <li>{@code S} representing the {@code short} primitive type</li>
* <li>{@code I} representing the {@code int} primitive type</li>
* <li>{@code J} representing the {@code long} primitive type</li>
* <li>{@code F} representing the {@code float} primitive type</li>
* <li>{@code D} representing the {@code double} primitive type</li>
* <li>{@code C} representing the {@code char} primitive type</li>
* <li>{@code Z} representing the {@code boolean} primitive type</li>
* <li>{@code V} representing void function return values</li>
* </ul>
* <p>
* <h4>Classes representing array classes</h4>
* <p>
* 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:
* </p>
* <ul>
* <li>{@code [I} representing the {@code int[]} type</li>
* <li>{@code [Ljava/lang/String;} representing the {@code String[]} type</li>
* <li>{@code [[[C} representing the {@code char[][][]} type (three dimensions!)</li>
* </ul>
*/
public final class Class<T> implements Serializable, AnnotatedElement, GenericDeclaration, Type {
private static final long serialVersionUID = 3206093459760846163L;
/** defining class loader, or NULL for the "bootstrap" system loader. */
private transient ClassLoader classLoader;
/**
* For array classes, the component class object for instanceof/checkcast (for String[][][],
* this will be String[][]). NULL for non-array classes.
*/
private transient Class<?> componentType;
/**
* DexCache of resolved constant pool entries. Will be null for certain VM-generated classes
* e.g. arrays and primitive classes.
*/
private transient DexCache dexCache;
/** static, private, and &lt;init&gt; methods. */
private transient ArtMethod[] directMethods;
/**
* Instance fields. These describe the layout of the contents of an Object. Note that only the
* fields directly declared by this class are listed in iFields; fields declared by a
* superclass are listed in the superclass's Class.iFields.
*
* All instance fields that refer to objects are guaranteed to be at the beginning of the field
* list. {@link Class#numReferenceInstanceFields} specifies the number of reference fields.
*/
private transient ArtField[] iFields;
/**
* The interface table (iftable_) contains pairs of a interface class and an array of the
* interface methods. There is one pair per interface supported by this class. That
* means one pair for each interface we support directly, indirectly via superclass, or
* indirectly via a superinterface. This will be null if neither we nor our superclass
* implement any interfaces.
*
* Why we need this: given "class Foo implements Face", declare "Face faceObj = new Foo()".
* Invoke faceObj.blah(), where "blah" is part of the Face interface. We can't easily use a
* single vtable.
*
* For every interface a concrete class implements, we create an array of the concrete vtable_
* methods for the methods in the interface.
*/
private transient Object[] ifTable;
/** Interface method table (imt), for quick "invoke-interface". */
private transient ArtMethod[] imTable;
/** Lazily computed name of this class; always prefer calling getName(). */
private transient String name;
/** Static fields */
private transient ArtField[] sFields;
/** The superclass, or NULL if this is java.lang.Object, an interface or primitive type. */
private transient Class<? super T> superClass;
/** If class verify fails, we must return same error on subsequent tries. */
private transient Class<?> verifyErrorClass;
/** Virtual methods defined in this class; invoked through vtable. */
private transient ArtMethod[] virtualMethods;
/**
* Virtual method table (vtable), for use by "invoke-virtual". The vtable from the superclass
* is copied in, and virtual methods from our class either replace those from the super or are
* appended. For abstract classes, methods may be created in the vtable that aren't in
* virtual_ methods_ for miranda methods.
*/
private transient ArtMethod[] vtable;
/** access flags; low 16 bits are defined by VM spec */
private transient int accessFlags;
/**
* Total size of the Class instance; used when allocating storage on GC heap.
* See also {@link Class#objectSize}.
*/
private transient int classSize;
/**
* tid used to check for recursive static initializer invocation.
*/
private transient int clinitThreadId;
/**
* Class def index from dex file. An index of 65535 indicates that there is no class definition,
* for example for an array type.
* TODO: really 16bits as type indices are 16bit.
*/
private transient int dexClassDefIndex;
/**
* Class type index from dex file, lazily computed. An index of 65535 indicates that the type
* index isn't known. Volatile to avoid double-checked locking bugs.
* TODO: really 16bits as type indices are 16bit.
*/
private transient volatile int dexTypeIndex;
/** Number of instance fields that are object references. */
private transient int numReferenceInstanceFields;
/** Number of static fields that are object references. */
private transient int numReferenceStaticFields;
/**
* Total object size; used when allocating storage on GC heap. For interfaces and abstract
* classes this will be zero. See also {@link Class#classSize}.
*/
private transient int objectSize;
/** Primitive type value, or 0 if not a primitive type; set for generated primitive classes. */
private transient int primitiveType;
/** Bitmap of offsets of iFields. */
private transient int referenceInstanceOffsets;
/** Bitmap of offsets of sFields. */
private transient int referenceStaticOffsets;
/** State of class initialization */
private transient int status;
private Class() {
// Prevent this class to be instantiated, instance should be created by JVM only
}
/**
* 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.
*
* <p>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.
*
* <p>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<Class<?>> result = new ArrayList<Class<?>>();
for (Class<?> c = this; c != null; c = c.superClass) {
for (Class<?> member : c.getDeclaredClasses()) {
if (Modifier.isPublic(member.getModifiers())) {
result.add(member);
}
}
}
return result.toArray(new Class[result.size()]);
}
@Override public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
return AnnotationAccess.getAnnotation(this, annotationType);
}
/**
* Returns an array containing all the annotations of this class. If there are no annotations
* then an empty array is returned.
*
* @see #getDeclaredAnnotations()
*/
@Override public Annotation[] getAnnotations() {
return AnnotationAccess.getAnnotations(this);
}
/**
* Returns the canonical name of this class. If this class does not have a
* canonical name as defined in the Java Language Specification, then the
* method returns {@code null}.
*/
public String getCanonicalName() {
if (isLocalClass() || isAnonymousClass())
return null;
if (isArray()) {
/*
* The canonical name of an array type depends on the (existence of)
* the component type's canonical name.
*/
String name = getComponentType().getCanonicalName();
if (name != null) {
return name + "[]";
}
} else if (isMemberClass()) {
/*
* The canonical name of an inner class depends on the (existence
* of) the declaring class' canonical name.
*/
String name = getDeclaringClass().getCanonicalName();
if (name != null) {
return name + "." + getSimpleName();
}
} else {
/*
* The canonical name of a top-level class or primitive type is
* equal to the fully qualified name.
*/
return getName();
}
/*
* Other classes don't have a canonical name.
*/
return null;
}
/**
* Returns the class loader which was used to load the class represented by
* this {@code Class}. Implementations are free to return {@code null} for
* classes that were loaded by the bootstrap class loader. The Android
* reference implementation, though, always returns a reference to an actual
* class loader.
*/
public ClassLoader getClassLoader() {
if (this.isPrimitive()) {
return null;
}
ClassLoader loader = getClassLoaderImpl();
if (loader == null) {
loader = BootClassLoader.getInstance();
}
return loader;
}
/**
* This must be provided by the VM vendor, as it is used by other provided
* class implementations in this package. Outside of this class, it is used
* by SecurityManager.classLoaderDepth(),
* currentClassLoader() and currentLoadedClass(). Return the ClassLoader for
* this Class without doing any security checks. The bootstrap ClassLoader
* is returned, unlike getClassLoader() which returns null in place of the
* bootstrap ClassLoader.
*/
ClassLoader getClassLoaderImpl() {
ClassLoader loader = classLoader;
return loader == null ? BootClassLoader.getInstance() : loader;
}
/**
* Returns a {@code Class} object which represents the component type if
* this class represents an array type. Returns {@code null} if this class
* does not represent an array type. The component type of an array type is
* the type of the elements of the array.
*/
public Class<?> getComponentType() {
return componentType;
}
/**
* Returns the dex file from which this class was loaded.
*
* @hide
*/
public Dex getDex() {
if (dexCache == null) {
return null;
}
return dexCache.getDex();
}
/**
* Returns a string from the dex cache, computing the string from the dex file if necessary.
*
* @hide
*/
public String getDexCacheString(Dex dex, int dexStringIndex) {
String[] dexCacheStrings = dexCache.strings;
String s = dexCacheStrings[dexStringIndex];
if (s == null) {
s = dex.strings().get(dexStringIndex).intern();
dexCacheStrings[dexStringIndex] = s;
}
return s;
}
/**
* Returns a resolved type from the dex cache, computing the type from the dex file if
* necessary.
*
* @hide
*/
public Class<?> getDexCacheType(Dex dex, int dexTypeIndex) {
Class<?>[] dexCacheResolvedTypes = dexCache.resolvedTypes;
Class<?> resolvedType = dexCacheResolvedTypes[dexTypeIndex];
if (resolvedType == null) {
int descriptorIndex = dex.typeIds().get(dexTypeIndex);
String descriptor = getDexCacheString(dex, descriptorIndex);
resolvedType = InternalNames.getClass(getClassLoader(), descriptor);
dexCacheResolvedTypes[dexTypeIndex] = resolvedType;
}
return resolvedType;
}
/**
* Returns a {@code Constructor} object which represents the public
* constructor matching the given parameter types.
* {@code (Class[]) null} is equivalent to the empty array.
*
* @throws NoSuchMethodException
* if the constructor cannot be found.
* @see #getDeclaredConstructor(Class[])
*/
public Constructor<T> getConstructor(Class<?>... parameterTypes) throws NoSuchMethodException {
return getConstructor(parameterTypes, true);
}
/**
* Returns a {@code Constructor} object which represents the constructor
* matching the specified parameter types that is declared by the class
* represented by this {@code Class}.
* {@code (Class[]) null} is equivalent to the empty array.
*
* @throws NoSuchMethodException
* if the requested constructor cannot be found.
* @see #getConstructor(Class[])
*/
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
throws NoSuchMethodException {
return getConstructor(parameterTypes, false);
}
/**
* Returns a constructor with the given parameters.
*
* @param publicOnly true to only return public constructores.
* @param parameterTypes argument types to match the constructor's.
*/
private Constructor<T> getConstructor(Class<?>[] parameterTypes, boolean publicOnly)
throws NoSuchMethodException {
if (parameterTypes == null) {
parameterTypes = EmptyArray.CLASS;
}
for (Class<?> c : parameterTypes) {
if (c == null) {
throw new NoSuchMethodException("parameter type is null");
}
}
Constructor<T> result = getDeclaredConstructorInternal(parameterTypes);
if (result == null || publicOnly && !Modifier.isPublic(result.getAccessFlags())) {
throw new NoSuchMethodException("<init> " + Arrays.toString(parameterTypes));
}
return result;
}
/**
* Returns the constructor with the given parameters if it is defined by this class; null
* otherwise. This may return a non-public member.
*
* @param args the types of the parameters to the constructor.
*/
private Constructor<T> getDeclaredConstructorInternal(Class<?>[] args) {
if (directMethods != null) {
for (ArtMethod m : directMethods) {
int modifiers = m.getAccessFlags();
if (Modifier.isStatic(modifiers)) {
// skip <clinit> which is a static constructor
continue;
}
if (!Modifier.isConstructor(modifiers)) {
continue;
}
if (!ArtMethod.equalConstructorParameters(m, args)) {
continue;
}
return new Constructor<T>(m);
}
}
return null;
}
/**
* Returns an array containing {@code Constructor} objects for all public
* constructors for this {@code Class}. If there
* are no public constructors or if this {@code Class} represents an array
* class, a primitive type or void then an empty array is returned.
*
* @see #getDeclaredConstructors()
*/
public Constructor<?>[] getConstructors() {
ArrayList<Constructor<T>> constructors = new ArrayList();
getDeclaredConstructors(true, constructors);
return constructors.toArray(new Constructor[constructors.size()]);
}
/**
* Returns an array containing {@code Constructor} objects for all
* constructors declared in the class represented by this {@code Class}. If
* there are no constructors or if this {@code Class} represents an array
* class, a primitive type or void then an empty array is returned.
*
* @see #getConstructors()
*/
public Constructor<?>[] getDeclaredConstructors() {
ArrayList<Constructor<T>> constructors = new ArrayList();
getDeclaredConstructors(false, constructors);
return constructors.toArray(new Constructor[constructors.size()]);
}
private void getDeclaredConstructors(boolean publicOnly, List<Constructor<T>> constructors) {
if (directMethods != null) {
for (ArtMethod m : directMethods) {
int modifiers = m.getAccessFlags();
if (!publicOnly || Modifier.isPublic(modifiers)) {
if (Modifier.isStatic(modifiers)) {
// skip <clinit> which is a static constructor
continue;
}
if (Modifier.isConstructor(modifiers)) {
constructors.add(new Constructor<T>(m));
}
}
}
}
}
/**
* Returns a {@code Method} object which represents the method matching the
* specified name and parameter types that is declared by the class
* represented by this {@code Class}.
*
* @param name
* the requested method's name.
* @param parameterTypes
* the parameter types of the requested method.
* {@code (Class[]) null} is equivalent to the empty array.
* @return the method described by {@code name} and {@code parameterTypes}.
* @throws NoSuchMethodException
* if the requested constructor cannot be found.
* @throws NullPointerException
* if {@code name} is {@code null}.
* @see #getMethod(String, Class[])
*/
public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
throws NoSuchMethodException {
return getMethod(name, parameterTypes, false);
}
/**
* Returns a {@code Method} object which represents the public method with
* the specified name and parameter types.
* {@code (Class[]) null} is equivalent to the empty array.
* This method first searches the
* class C represented by this {@code Class}, then the superclasses of C and
* finally the interfaces implemented by C and finally the superclasses of C
* for a method with matching name.
*
* @throws NoSuchMethodException
* if the method cannot be found.
* @see #getDeclaredMethod(String, Class[])
*/
public Method getMethod(String name, Class<?>... parameterTypes) throws NoSuchMethodException {
return getMethod(name, parameterTypes, true);
}
private Method getMethod(String name, Class<?>[] parameterTypes, boolean recursivePublicMethods)
throws NoSuchMethodException {
if (name == null) {
throw new NullPointerException("name == null");
}
if (parameterTypes == null) {
parameterTypes = EmptyArray.CLASS;
}
for (Class<?> c : parameterTypes) {
if (c == null) {
throw new NoSuchMethodException("parameter type is null");
}
}
Method result = recursivePublicMethods ? getPublicMethodRecursive(name, parameterTypes)
: getDeclaredMethodInternal(name, parameterTypes);
// Fail if we didn't find the method or it was expected to be public.
if (result == null ||
(recursivePublicMethods && !Modifier.isPublic(result.getAccessFlags()))) {
throw new NoSuchMethodException(name + " " + Arrays.toString(parameterTypes));
}
return result;
}
private Method getPublicMethodRecursive(String name, Class<?>[] parameterTypes) {
// search superclasses
for (Class<?> c = this; c != null; c = c.getSuperclass()) {
Method result = c.getDeclaredMethodInternal(name, parameterTypes);
if (result != null && Modifier.isPublic(result.getAccessFlags())) {
return result;
}
}
// search iftable which has a flattened and uniqued list of interfaces
Object[] iftable = ifTable;
if (iftable != null) {
for (int i = 0; i < iftable.length; i += 2) {
Class<?> ifc = (Class<?>) iftable[i];
Method result = ifc.getPublicMethodRecursive(name, parameterTypes);
if (result != null && Modifier.isPublic(result.getAccessFlags())) {
return result;
}
}
}
return null;
}
/**
* Returns the method if it is defined by this class; null otherwise. This may return a
* non-public member.
*
* @param name the method name
* @param args the method's parameter types
*/
private Method getDeclaredMethodInternal(String name, Class<?>[] args) {
// Covariant return types permit the class to define multiple
// methods with the same name and parameter types. Prefer to
// return a non-synthetic method in such situations. We may
// still return a synthetic method to handle situations like
// escalated visibility. We never return miranda methods that
// were synthesized by the VM.
int skipModifiers = Modifier.MIRANDA | Modifier.SYNTHETIC;
ArtMethod artMethodResult = null;
if (virtualMethods != null) {
for (ArtMethod m : virtualMethods) {
String methodName = ArtMethod.getMethodName(m);
if (!name.equals(methodName)) {
continue;
}
if (!ArtMethod.equalMethodParameters(m, args)) {
continue;
}
int modifiers = m.getAccessFlags();
if ((modifiers & skipModifiers) == 0) {
return new Method(m);
}
if ((modifiers & Modifier.MIRANDA) == 0) {
// Remember as potential result if it's not a miranda method.
artMethodResult = m;
}
}
}
if (artMethodResult == null) {
if (directMethods != null) {
for (ArtMethod m : directMethods) {
int modifiers = m.getAccessFlags();
if (Modifier.isConstructor(modifiers)) {
continue;
}
String methodName = ArtMethod.getMethodName(m);
if (!name.equals(methodName)) {
continue;
}
if (!ArtMethod.equalMethodParameters(m, args)) {
continue;
}
if ((modifiers & skipModifiers) == 0) {
return new Method(m);
}
// Direct methods cannot be miranda methods,
// so this potential result must be synthetic.
artMethodResult = m;
}
}
}
if (artMethodResult == null) {
return null;
}
return new Method(artMethodResult);
}
/**
* Returns an array containing {@code Method} objects for all methods
* declared in the class represented by this {@code Class}. If there are no
* methods or if this {@code Class} represents an array class, a primitive
* type or void then an empty array is returned.
*
* @see #getMethods()
*/
public Method[] getDeclaredMethods() {
int initial_size = virtualMethods == null ? 0 : virtualMethods.length;
initial_size += directMethods == null ? 0 : directMethods.length;
ArrayList<Method> methods = new ArrayList<Method>(initial_size);
getDeclaredMethods(false, methods);
Method[] result = methods.toArray(new Method[methods.size()]);
for (Method m : result) {
// Throw NoClassDefFoundError if types cannot be resolved.
m.getReturnType();
m.getParameterTypes();
}
return result;
}
/**
* Returns the list of methods without performing any security checks
* first. If no methods exist, an empty array is returned.
*/
private void getDeclaredMethods(boolean publicOnly, List<Method> methods) {
if (virtualMethods != null) {
for (ArtMethod m : virtualMethods) {
int modifiers = m.getAccessFlags();
if (!publicOnly || Modifier.isPublic(modifiers)) {
// Add non-miranda virtual methods.
if ((modifiers & Modifier.MIRANDA) == 0) {
methods.add(new Method(m));
}
}
}
}
if (directMethods != null) {
for (ArtMethod m : directMethods) {
int modifiers = m.getAccessFlags();
if (!publicOnly || Modifier.isPublic(modifiers)) {
// Add non-constructor direct/static methods.
if (!Modifier.isConstructor(modifiers)) {
methods.add(new Method(m));
}
}
}
}
}
/**
* Returns an array containing {@code Method} objects for all public methods
* for the class C represented by this {@code Class}. Methods 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.
*
* <p>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<Method> methods = new ArrayList<Method>();
getPublicMethodsInternal(methods);
/*
* Remove duplicate methods defined by superclasses and
* interfaces, preferring to keep methods declared by derived
* types.
*/
CollectionUtils.removeDuplicates(methods, Method.ORDER_BY_SIGNATURE);
return methods.toArray(new Method[methods.size()]);
}
/**
* Populates {@code result} with public methods defined by this class, its
* superclasses, and all implemented interfaces, including overridden methods.
*/
private void getPublicMethodsInternal(List<Method> result) {
getDeclaredMethods(true, result);
if (!isInterface()) {
// Search superclasses, for interfaces don't search java.lang.Object.
for (Class<?> c = superClass; c != null; c = c.superClass) {
c.getDeclaredMethods(true, result);
}
}
// Search iftable which has a flattened and uniqued list of interfaces.
Object[] iftable = ifTable;
if (iftable != null) {
for (int i = 0; i < iftable.length; i += 2) {
Class<?> ifc = (Class<?>) iftable[i];
ifc.getDeclaredMethods(true, result);
}
}
}
/**
* Returns the annotations that are directly defined on the class
* represented by this {@code Class}. Annotations that are inherited are not
* included in the result. If there are no annotations at all, an empty
* array is returned.
*
* @see #getAnnotations()
*/
@Override public Annotation[] getDeclaredAnnotations() {
List<Annotation> result = AnnotationAccess.getDeclaredAnnotations(this);
return result.toArray(new Annotation[result.size()]);
}
/**
* Returns an array containing {@code Class} objects for all classes,
* interfaces, enums and annotations that are members of this class.
*/
public Class<?>[] getDeclaredClasses() {
return AnnotationAccess.getMemberClasses(this);
}
/**
* Returns a {@code Field} object for the field with the given name
* which is declared in the class represented by this {@code Class}.
*
* @throws NoSuchFieldException if the requested field can not be found.
* @see #getField(String)
*/
public Field getDeclaredField(String name) throws NoSuchFieldException {
if (name == null) {
throw new NullPointerException("name == null");
}
Field result = getDeclaredFieldInternal(name);
if (result == null) {
throw new NoSuchFieldException(name);
} else {
result.getType(); // Throw NoClassDefFoundError if type cannot be resolved.
}
return result;
}
/**
* Returns an array containing {@code Field} objects for all fields declared
* in the class represented by this {@code Class}. If there are no fields or
* if this {@code Class} represents an array class, a primitive type or void
* then an empty array is returned.
*
* @see #getFields()
*/
public Field[] getDeclaredFields() {
int initial_size = sFields == null ? 0 : sFields.length;
initial_size += iFields == null ? 0 : iFields.length;
ArrayList<Field> fields = new ArrayList(initial_size);
getDeclaredFields(false, fields);
Field[] result = fields.toArray(new Field[fields.size()]);
for (Field f : result) {
f.getType(); // Throw NoClassDefFoundError if type cannot be resolved.
}
return result;
}
private void getDeclaredFields(boolean publicOnly, List<Field> fields) {
if (iFields != null) {
for (ArtField f : iFields) {
if (!publicOnly || Modifier.isPublic(f.getAccessFlags())) {
fields.add(new Field(f));
}
}
}
if (sFields != null) {
for (ArtField f : sFields) {
if (!publicOnly || Modifier.isPublic(f.getAccessFlags())) {
fields.add(new Field(f));
}
}
}
}
/**
* Returns the field if it is defined by this class; null otherwise. This
* may return a non-public member.
*/
private Field getDeclaredFieldInternal(String name) {
if (iFields != null) {
for (ArtField f : iFields) {
if (f.getName().equals(name)) {
return new Field(f);
}
}
}
if (sFields != null) {
for (ArtField f : sFields) {
if (f.getName().equals(name)) {
return new Field(f);
}
}
}
return null;
}
/**
* Returns the class that this class is a member of, or {@code null} if this
* class is a top-level class, a primitive, an array, or defined within a
* method or constructor.
*/
public Class<?> getDeclaringClass() {
if (AnnotationAccess.isAnonymousClass(this)) {
return null;
}
return AnnotationAccess.getEnclosingClass(this);
}
/**
* Returns the class enclosing this class. For most classes this is the same
* as the {@link #getDeclaringClass() declaring class}. For classes defined
* within a method or constructor (typically anonymous inner classes), this
* is the declaring class of that member.
*/
public Class<?> getEnclosingClass() {
Class<?> declaringClass = getDeclaringClass();
if (declaringClass != null) {
return declaringClass;
}
AccessibleObject member = AnnotationAccess.getEnclosingMethodOrConstructor(this);
if (member != null) {
return ((Member) member).getDeclaringClass();
}
return AnnotationAccess.getEnclosingClass(this);
}
/**
* Returns the enclosing {@code Constructor} of this {@code Class}, if it is an
* anonymous or local/automatic class; otherwise {@code null}.
*/
public Constructor<?> getEnclosingConstructor() {
if (classNameImpliesTopLevel()) {
return null;
}
AccessibleObject result = AnnotationAccess.getEnclosingMethodOrConstructor(this);
return result instanceof Constructor ? (Constructor<?>) result : null;
}
/**
* Returns the enclosing {@code Method} of this {@code Class}, if it is an
* anonymous or local/automatic class; otherwise {@code null}.
*/
public Method getEnclosingMethod() {
if (classNameImpliesTopLevel()) {
return null;
}
AccessibleObject result = AnnotationAccess.getEnclosingMethodOrConstructor(this);
return result instanceof Method ? (Method) result : null;
}
/**
* Returns true if this class is definitely a top level class, or false if
* a more expensive check like {@link #getEnclosingClass()} is necessary.
*
* <p>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 <strong>does
* not</strong> 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.
*
* <p>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<Field> fields = new ArrayList<Field>();
getPublicFieldsRecursive(fields);
Field[] result = fields.toArray(new Field[fields.size()]);
for (Field f : result) {
f.getType(); // Throw NoClassDefFoundError if type cannot be resolved.
}
return result;
}
/**
* Populates {@code result} with public fields defined by this class, its
* superclasses, and all implemented interfaces.
*/
private void getPublicFieldsRecursive(List<Field> result) {
// search superclasses
for (Class<?> c = this; c != null; c = c.superClass) {
c.getDeclaredFields(true, result);
}
// search iftable which has a flattened and uniqued list of interfaces
Object[] iftable = ifTable;
if (iftable != null) {
for (int i = 0; i < iftable.length; i += 2) {
Class<?> ifc = (Class<?>) iftable[i];
ifc.getDeclaredFields(true, result);
}
}
}
/**
* Returns the {@link Type}s of the interfaces that this {@code Class} directly
* implements. If the {@code Class} represents a primitive type or {@code
* void} then an empty array is returned.
*/
public Type[] getGenericInterfaces() {
Type[] result;
synchronized (Caches.genericInterfaces) {
result = Caches.genericInterfaces.get(this);
if (result == null) {
String annotationSignature = AnnotationAccess.getSignature(this);
if (annotationSignature == null) {
result = getInterfaces();
} else {
GenericSignatureParser parser = new GenericSignatureParser(getClassLoader());
parser.parseForClass(this, annotationSignature);
result = Types.getTypeArray(parser.interfaceTypes, false);
}
Caches.genericInterfaces.put(this, result);
}
}
return (result.length == 0) ? result : result.clone();
}
/**
* Returns the {@code Type} that represents the superclass of this {@code
* class}.
*/
public Type getGenericSuperclass() {
Type genericSuperclass = getSuperclass();
// This method is specified to return null for all cases where getSuperclass
// returns null, i.e, for primitives, interfaces, void and java.lang.Object.
if (genericSuperclass == null) {
return null;
}
String annotationSignature = AnnotationAccess.getSignature(this);
if (annotationSignature != null) {
GenericSignatureParser parser = new GenericSignatureParser(getClassLoader());
parser.parseForClass(this, annotationSignature);
genericSuperclass = parser.superclassType;
}
return Types.getType(genericSuperclass);
}
/**
* Returns an array of {@code Class} objects that match the interfaces
* in the {@code implements} declaration of the class represented
* by this {@code Class}. The order of the elements in the array is
* identical to the order in the original class declaration. If the class
* does not implement any interfaces, an empty array is returned.
*
* <p>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<Class<T>>[] getTypeParameters() {
String annotationSignature = AnnotationAccess.getSignature(this);
if (annotationSignature == null) {
return EmptyArray.TYPE_VARIABLE;
}
GenericSignatureParser parser = new GenericSignatureParser(getClassLoader());
parser.parseForClass(this, annotationSignature);
return parser.formalTypeParameters;
}
/**
* Tests whether this {@code Class} represents an annotation class.
*/
public boolean isAnnotation() {
final int ACC_ANNOTATION = 0x2000; // not public in reflect.Modifier
return (accessFlags & ACC_ANNOTATION) != 0;
}
@Override public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
return AnnotationAccess.isAnnotationPresent(this, annotationType);
}
/**
* Tests whether the class represented by this {@code Class} is
* anonymous.
*/
public boolean isAnonymousClass() {
return AnnotationAccess.isAnonymousClass(this);
}
/**
* Tests whether the class represented by this {@code Class} is an array class.
*/
public boolean isArray() {
return getComponentType() != null;
}
/**
* Is this a runtime created proxy class?
*
* @hide
*/
public boolean isProxy() {
return (accessFlags & 0x00040000) != 0;
}
/**
* Can {@code c} be assigned to this class? For example, String can be assigned to Object
* (by an upcast), however, an Object cannot be assigned to a String as a potentially exception
* throwing downcast would be necessary. Similarly for interfaces, a class that implements (or
* an interface that extends) another can be assigned to its parent, but not vice-versa. All
* Classes may assign to themselves. Classes for primitive types may not assign to each other.
*
* @param c the class to check.
* @return {@code true} if {@code c} can be assigned to the class
* represented by this {@code Class}; {@code false} otherwise.
* @throws NullPointerException if {@code c} is {@code null}.
*/
public boolean isAssignableFrom(Class<?> c) {
if (this == c) {
return true; // Can always assign to things of the same type.
} else if (this == Object.class) {
return !c.isPrimitive(); // Can assign any reference to java.lang.Object.
} else if (isArray()) {
return c.isArray() && componentType.isAssignableFrom(c.componentType);
} else if (isInterface()) {
// Search iftable which has a flattened and uniqued list of interfaces.
Object[] iftable = c.ifTable;
if (iftable != null) {
for (int i = 0; i < iftable.length; i += 2) {
Class<?> ifc = (Class<?>) iftable[i];
if (ifc == this) {
return true;
}
}
}
return false;
} else {
if (!c.isInterface()) {
for (c = c.superClass; c != null; c = c.superClass) {
if (c == this) {
return true;
}
}
}
return false;
}
}
/**
* Tests whether the class represented by this {@code Class} is an
* {@code enum}.
*/
public boolean isEnum() {
return (getSuperclass() == Enum.class) && ((accessFlags & 0x4000) != 0);
}
/**
* Tests whether the given object can be cast to the class
* represented by this {@code Class}. This is the runtime version of the
* {@code instanceof} operator.
*
* @return {@code true} if {@code object} can be cast to the type
* represented by this {@code Class}; {@code false} if {@code
* object} is {@code null} or cannot be cast.
*/
public boolean isInstance(Object object) {
if (object == null) {
return false;
}
return isAssignableFrom(object.getClass());
}
/**
* Tests whether this {@code Class} represents an interface.
*/
public boolean isInterface() {
return (accessFlags & Modifier.INTERFACE) != 0;
}
/**
* Tests whether the class represented by this {@code Class} is defined
* locally.
*/
public boolean isLocalClass() {
return !classNameImpliesTopLevel()
&& AnnotationAccess.getEnclosingMethodOrConstructor(this) != null
&& !isAnonymousClass();
}
/**
* Tests whether the class represented by this {@code Class} is a member
* class.
*/
public boolean isMemberClass() {
return getDeclaringClass() != null;
}
/**
* Tests whether this {@code Class} represents a primitive type.
*/
public boolean isPrimitive() {
return primitiveType != 0;
}
/**
* Tests whether this {@code Class} represents a synthetic type.
*/
public boolean isSynthetic() {
final int ACC_SYNTHETIC = 0x1000; // not public in reflect.Modifier
return (accessFlags & ACC_SYNTHETIC) != 0;
}
/**
* Indicates whether this {@code Class} or its parents override finalize.
*
* @hide
*/
public boolean isFinalizable() {
final int ACC_CLASS_IS_FINALIZABLE = 0x80000000; // not public in reflect.Modifier
return (accessFlags & ACC_CLASS_IS_FINALIZABLE) != 0;
}
/**
* Returns a new instance of the class represented by this {@code Class},
* created by invoking the default (that is, zero-argument) constructor. If
* there is no such constructor, or if the creation fails (either because of
* a lack of available memory or because an exception is thrown by the
* constructor), an {@code InstantiationException} is thrown. If the default
* constructor exists but is not accessible from the context where this
* method is invoked, an {@code IllegalAccessException} is thrown.
*
* @throws IllegalAccessException
* if the default constructor is not visible.
* @throws InstantiationException
* if the instance cannot be created.
*/
public T newInstance() throws InstantiationException, IllegalAccessException {
if (isPrimitive() || isInterface() || isArray() || Modifier.isAbstract(accessFlags)) {
throw new InstantiationException(this + " cannot be instantiated");
}
Class<?> caller = VMStack.getStackClass1();
if (!caller.canAccess(this)) {
throw new IllegalAccessException(this + " is not accessible from " + caller);
}
Constructor<T> init;
try {
init = getDeclaredConstructor();
} catch (NoSuchMethodException e) {
InstantiationException t =
new InstantiationException(this + " has no zero argument constructor");
t.initCause(e);
throw t;
}
if (!caller.canAccessMember(this, init.getAccessFlags())) {
throw new IllegalAccessException(init + " is not accessible from " + caller);
}
try {
return init.newInstance(null, init.isAccessible());
} catch (InvocationTargetException e) {
SneakyThrow.sneakyThrow(e.getCause());
return null; // Unreachable.
}
}
private boolean canAccess(Class<?> c) {
if(Modifier.isPublic(c.accessFlags)) {
return true;
}
return inSamePackage(c);
}
private boolean canAccessMember(Class<?> memberClass, int memberModifiers) {
if (memberClass == this || Modifier.isPublic(memberModifiers)) {
return true;
}
if (Modifier.isPrivate(memberModifiers)) {
return false;
}
if (Modifier.isProtected(memberModifiers)) {
for (Class<?> parent = this.superClass; parent != null; parent = parent.superClass) {
if (parent == memberClass) {
return true;
}
}
}
return inSamePackage(memberClass);
}
private boolean inSamePackage(Class<?> c) {
if (classLoader != c.classLoader) {
return false;
}
String packageName1 = getPackageName$();
String packageName2 = c.getPackageName$();
if (packageName1 == null) {
return packageName2 == null;
} else if (packageName2 == null) {
return false;
} else {
return packageName1.equals(packageName2);
}
}
@Override
public String toString() {
if (isPrimitive()) {
return getSimpleName();
} else {
return (isInterface() ? "interface " : "class ") + getName();
}
}
/**
* Returns the {@code Package} of which the class represented by this
* {@code Class} is a member. Returns {@code null} if no {@code Package}
* object was created by the class loader of the class.
*/
public Package getPackage() {
// TODO This might be a hack, but the VM doesn't have the necessary info.
ClassLoader loader = getClassLoader();
if (loader != null) {
String packageName = getPackageName$();
return packageName != null ? loader.getPackage(packageName) : null;
}
return null;
}
/**
* Returns the package name of this class. This returns null for classes in
* the default package.
*
* @hide
*/
public String getPackageName$() {
String name = getName();
int last = name.lastIndexOf('.');
return last == -1 ? null : name.substring(0, last);
}
/**
* Returns the assertion status for the class represented by this {@code
* Class}. Assertion is enabled / disabled based on the class loader,
* package or class default at runtime.
*/
public boolean desiredAssertionStatus() {
return false;
}
/**
* Casts this {@code Class} to represent a subclass of the given class.
* If successful, this {@code Class} is returned; otherwise a {@code
* ClassCastException} is thrown.
*
* @throws ClassCastException
* if this {@code Class} cannot be cast to the given type.
*/
@SuppressWarnings("unchecked")
public <U> Class<? extends U> asSubclass(Class<U> c) {
if (c.isAssignableFrom(this)) {
return (Class<? extends U>)this;
}
String actualClassName = this.getName();
String desiredClassName = c.getName();
throw new ClassCastException(actualClassName + " cannot be cast to " + desiredClassName);
}
/**
* Casts the given object to the type represented by this {@code Class}.
* If the object is {@code null} then the result is also {@code null}.
*
* @throws ClassCastException
* if the object cannot be cast to the given type.
*/
@SuppressWarnings("unchecked")
public T cast(Object obj) {
if (obj == null) {
return null;
} else if (this.isInstance(obj)) {
return (T)obj;
}
String actualClassName = obj.getClass().getName();
String desiredClassName = this.getName();
throw new ClassCastException(actualClassName + " cannot be cast to " + desiredClassName);
}
/**
* The class def of this class in its own Dex, or -1 if there is no class def.
*
* @hide
*/
public int getDexClassDefIndex() {
return (dexClassDefIndex == 65535) ? -1 : dexClassDefIndex;
}
/**
* The type index of this class in its own Dex, or -1 if it is unknown. If a class is referenced
* by multiple Dex files, it will have a different type index in each. Dex files support 65534
* type indices, with 65535 representing no index.
*
* @hide
*/
public int getDexTypeIndex() {
int typeIndex = dexTypeIndex;
if (typeIndex != 65535) {
return typeIndex;
}
synchronized (this) {
typeIndex = dexTypeIndex;
if (typeIndex == 65535) {
if (dexClassDefIndex >= 0) {
typeIndex = getDex().typeIndexFromClassDefIndex(dexClassDefIndex);
} else {
typeIndex = getDex().findTypeIndex(InternalNames.getInternalName(this));
if (typeIndex < 0) {
typeIndex = -1;
}
}
dexTypeIndex = typeIndex;
}
}
return typeIndex;
}
/**
* The annotation directory offset of this class in its own Dex, or 0 if it
* is unknown.
*
* TODO: 0 is a sentinel that means 'no annotations directory'; this should be -1 if unknown
*
* @hide
*/
public int getDexAnnotationDirectoryOffset() {
Dex dex = getDex();
if (dex == null) {
return 0;
}
int classDefIndex = getDexClassDefIndex();
if (classDefIndex < 0) {
return 0;
}
return dex.annotationDirectoryOffsetFromClassDefIndex(classDefIndex);
}
private static class Caches {
/**
* Cache to avoid frequent recalculation of generic interfaces, which is generally uncommon.
* Sized sufficient to allow ConcurrentHashMapTest to run without recalculating its generic
* interfaces (required to avoid time outs). Validated by running reflection heavy code
* such as applications using Guice-like frameworks.
*/
private static final BasicLruCache<Class, Type[]> genericInterfaces
= new BasicLruCache<Class, Type[]>(8);
}
}