blob: 7c41f88402ec8fb00074823d95d939e34078ef97 [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.
*/
package java.lang;
import static org.apache.harmony.vm.ClassFormat.ACC_ANNOTATION;
import static org.apache.harmony.vm.ClassFormat.ACC_ENUM;
import static org.apache.harmony.vm.ClassFormat.ACC_INTERFACE;
import static org.apache.harmony.vm.ClassFormat.ACC_SYNTHETIC;
import java.io.Externalizable;
import java.io.InputStream;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.annotation.Inherited;
import java.lang.ref.SoftReference;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.GenericDeclaration;
import java.lang.reflect.GenericSignatureFormatError;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.MalformedParameterizedTypeException;
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.AccessController;
import java.security.AllPermission;
import java.security.Permissions;
import java.security.PrivilegedAction;
import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Map;
import org.apache.harmony.lang.RuntimePermissionCollection;
import org.apache.harmony.lang.reflect.Reflection;
import org.apache.harmony.lang.reflect.parser.Parser;
import org.apache.harmony.vm.VMGenericsAndAnnotations;
import org.apache.harmony.vm.VMStack;
/**
* Runtime representation of a class
*
* @author Evgueni Brevnov, Serguei S. Zapreyev, Alexey V. Varlamov
*/
public final class Class<T> implements Serializable, AnnotatedElement, GenericDeclaration, Type {
/**
* Global/system assertion status
*
* package private to access from the java.lang.ClassLoader class.
*/
static volatile boolean disableAssertions =
VMExecutionEngine.getAssertionStatus(null, false, 0) <= 0;
static ProtectionDomain systemDomain;
private static final long serialVersionUID = 3206093459760846163L;
private static final Class<Cloneable> CLONEABLE_CLASS = Cloneable.class;
@SuppressWarnings("unchecked")
private static final Class<Enum> ENUM_CLASS = Enum.class;
private static final Class<Externalizable> EXTERNALIZABLE_CLASS = Externalizable.class;
private static final Class<Inherited> INHERITED_CLASS = Inherited.class;
private static final Class<Object> OBJECT_CLASS = Object.class;
private static final Class<Serializable> SERIALIZABLE_CLASS = Serializable.class;
public static Class<?> forName(String name) throws ClassNotFoundException {
return forName(name, true, VMClassRegistry.getClassLoader(VMStack
.getCallerClass(0)));
}
public static Class<?> forName(String name, boolean initialize,
ClassLoader classLoader) throws ClassNotFoundException {
if (name == null) {
throw new NullPointerException();
}
if(name.indexOf("/") != -1) {
throw new ClassNotFoundException(name);
}
Class<?> clazz = null;
if (classLoader == null) {
SecurityManager sc = System.getSecurityManager();
if (sc != null &&
VMClassRegistry.getClassLoader(VMStack.getCallerClass(0)) != null) {
sc.checkPermission(RuntimePermissionCollection.GET_CLASS_LOADER_PERMISSION);
}
clazz = VMClassRegistry.loadBootstrapClass(name);
} else {
int dims = 0;
int len = name.length();
while (dims < len && name.charAt(dims) == '[') dims++;
if (dims > 0 && len > dims + 1
&& name.charAt(dims) == 'L' && name.endsWith(";")) {
/*
* an array of a reference type is requested.
* do not care of arrays of primitives as
* they are perfectly loaded by bootstrap classloader.
*/
try {
clazz = classLoader.loadClass(name.substring(dims + 1, len - 1));
} catch (ClassNotFoundException ignore) {}
if (clazz != null ) {
clazz = VMClassRegistry.loadArray(clazz, dims);
}
} else {
clazz = classLoader.loadClass(name);
}
}
if(clazz == null) {
throw new ClassNotFoundException(name);
}
if(classLoader != null) {
/*
* Although class loader may have had a chance to register itself as
* initiating for requested class, there may occur a classloader
* which overloads loadClass method (though it is not recommended by
* J2SE specification). Try to register initiating loader for clazz
* from here again
*/
classLoader.registerInitiatedClass(clazz);
}
if (initialize) {
VMClassRegistry.initializeClass(clazz);
} else {
VMClassRegistry.linkClass(clazz);
}
return clazz;
}
/**
* VMI method
*/
static final Class<?>[] getStackClasses(int maxDepth, boolean stopAtPrivileged) {
return VMStack.getClasses(maxDepth, stopAtPrivileged);
}
/**
* Answers whether the arrays are equal
*/
static boolean isTypeMatches(Class<?>[] t1, Class<?>[] t2) {
if (t1 == null) {
return t2 == null || t2.length == 0;
}
if (t2 == null) {
return t1 == null || t1.length == 0;
}
if (t1.length != t2.length) {
return false;
}
for (int i = 0; i < t2.length; i++) {
if (t1[i] != t2[i]) {
return false;
}
}
return true;
}
private static Method findMatchingMethod(Method[] methods,
String methodName, Class<?>[] argumentTypes)
throws NoSuchMethodException {
Method matcher = null;
for (int i = 0; i < methods.length; i++) {
Method m = methods[i];
if (matcher != null
&& matcher.getDeclaringClass() != m.getDeclaringClass()) {
return matcher;
}
try {
if (methodName.equals(m.getName())
&& isTypeMatches(argumentTypes, m.getParameterTypes())
&& (matcher == null || matcher.getReturnType()
.isAssignableFrom(m.getReturnType()))) {
matcher = m;
}
} catch (LinkageError ignore) {
}
}
if (matcher == null) {
throw new NoSuchMethodException(methodName.toString()
+ printMethodSignature(argumentTypes));
}
return matcher;
}
private static String getParentName(String name) {
int dotPosition = name.lastIndexOf('.');
return dotPosition == -1 ? "" : name.substring(0, dotPosition);
}
private static String printMethodSignature(Class<?>[] types) {
StringBuffer sb = new StringBuffer("(");
if (types != null && types.length > 0) {
sb.append(types[0] != null ? types[0].getName() : "null");
for (int i = 1; i < types.length; i++) {
sb.append(", ");
sb.append(types[i] != null ? types[i].getName() : "null");
}
}
sb.append(")");
return sb.toString();
}
/**
* Provides strong referencing between the classloader
* and it's defined classes. Intended for class unloading implementation.
* @see java.lang.ClassLoader#loadedClasses
*/
ClassLoader definingLoader;
transient SoftReference<GACache> softCache;
private transient volatile ReflectionData _reflectionData;
private transient ProtectionDomain domain;
/** It is required for synchronization in newInstance method. */
private volatile boolean isDefaultConstructorInitialized;
/**
* Only VM can instantiate this class.
*/
private Class() {
}
/**
* Accessor for the reflection data field, which needs to have
* minimal thread-safety for consistency; this method encapsulates
* that.
*/
private ReflectionData getReflectionData() {
// read the volatile field once
final ReflectionData localData = _reflectionData;
if (localData == null){
// if null, construct, write to the field and return
return _reflectionData = new ReflectionData();
}
// else, just return the field
return localData;
}
private GACache getCache() {
GACache cache = null;
if (softCache != null) {
cache = softCache.get();
}
if (cache == null) {
softCache = new SoftReference<GACache>(cache = new GACache());
}
return cache;
}
public boolean desiredAssertionStatus() {
if (disableAssertions) {
return false;
}
ClassLoader loader = getClassLoaderImpl();
if (loader == null) {
// system class, status is controlled via cmdline only
return VMExecutionEngine.getAssertionStatus(this, true, 0) > 0;
}
// First check exact class name
String name = null;
Map<String, Boolean> m = loader.classAssertionStatus;
if (m != null && m.size() != 0)
{
name = getTopLevelClassName();
Boolean status = m.get(name);
if (status != null) {
return status.booleanValue();
}
}
if (!loader.clearAssertionStatus) {
int systemStatus = VMExecutionEngine.getAssertionStatus(this, false, 0);
if (systemStatus != 0) {
return systemStatus > 0;
}
}
// Next try (super)packages name(s) recursively
m = loader.packageAssertionStatus;
if (m != null && m.size() != 0) {
if (name == null) {
name = getName();
}
name = getParentName(name);
// if this class is in the default package,
// it is checked in the 1st iteration
do {
Boolean status = m.get(name);
if (status != null) {
return status.booleanValue();
}
} while ( (name = getParentName(name)).length() > 0);
}
if (!loader.clearAssertionStatus) {
int systemStatus = VMExecutionEngine.getAssertionStatus(this, true,
loader.defaultAssertionStatus);
if (systemStatus != 0) {
return systemStatus > 0;
}
}
// Finally check the default status
return loader.defaultAssertionStatus > 0;
}
/**
* Note: We don't check member access permission for each super class.
* Java 1.5 API specification doesn't require this check.
*/
public Class[] getClasses() {
checkMemberAccess(Member.PUBLIC);
Class<?> clss = this;
ArrayList<Class<?>> classes = null;
while (clss != null) {
Class<?>[] declared = VMClassRegistry.getDeclaredClasses(clss);
if (declared.length != 0) {
if (classes == null) {
classes = new ArrayList<Class<?>>();
}
for (Class<?> c : declared) {
if (Modifier.isPublic(c.getModifiers())) {
classes.add(c);
}
}
}
clss = clss.getSuperclass();
}
if (classes == null) {
return new Class[0];
} else {
return classes.toArray(new Class[classes.size()]);
}
}
public ClassLoader getClassLoader() {
ClassLoader loader = getClassLoaderImpl();
SecurityManager sc = System.getSecurityManager();
if (sc != null) {
ClassLoader callerLoader = VMClassRegistry.getClassLoader(VMStack
.getCallerClass(0));
if (callerLoader != null && !callerLoader.isSameOrAncestor(loader)) {
sc.checkPermission(RuntimePermissionCollection.GET_CLASS_LOADER_PERMISSION);
}
}
return loader;
}
public Class<?> getComponentType() {
if (!isArray()) {
return null;
}
return VMClassRegistry.getComponentType(this);
}
public Constructor<T> getConstructor(Class... argumentTypes)
throws NoSuchMethodException {
checkMemberAccess(Member.PUBLIC);
Constructor<T> ctors[] = getReflectionData().getPublicConstructors();
for (int i = 0; i < ctors.length; i++) {
Constructor<T> c = ctors[i];
try {
if (isTypeMatches(argumentTypes, c.getParameterTypes())) {
return Reflection.copyConstructor(c);
}
} catch (LinkageError ignore) {}
}
throw new NoSuchMethodException(getName()
+ printMethodSignature(argumentTypes));
}
@SuppressWarnings("unchecked")
public Constructor[] getConstructors() {
checkMemberAccess(Member.PUBLIC);
return Reflection.copyConstructors(getReflectionData().getPublicConstructors());
}
@SuppressWarnings("unchecked")
public Class[] getDeclaredClasses() {
checkMemberAccess(Member.DECLARED);
return VMClassRegistry.getDeclaredClasses(this);
}
@SuppressWarnings("unchecked")
public Constructor<T> getDeclaredConstructor(Class... argumentTypes)
throws NoSuchMethodException {
checkMemberAccess(Member.DECLARED);
return Reflection
.copyConstructor(getDeclaredConstructorInternal(argumentTypes));
}
@SuppressWarnings("unchecked")
public Constructor[] getDeclaredConstructors() {
checkMemberAccess(Member.DECLARED);
return Reflection.copyConstructors(getReflectionData().getDeclaredConstructors());
}
public Field getDeclaredField(String fieldName) throws NoSuchFieldException {
checkMemberAccess(Member.DECLARED);
final Field[] declaredFields = getReflectionData().getDeclaredFields();
for (int i = 0; i < declaredFields.length; i++) {
Field f = declaredFields[i];
if (fieldName.equals(f.getName())) {
return Reflection.copyField(f);
}
}
throw new NoSuchFieldException(fieldName.toString());
}
public Field[] getDeclaredFields() {
checkMemberAccess(Member.DECLARED);
return Reflection.copyFields(getReflectionData().getDeclaredFields());
}
@SuppressWarnings("unchecked")
public Method getDeclaredMethod(String methodName, Class... argumentTypes)
throws NoSuchMethodException {
checkMemberAccess(Member.DECLARED);
return Reflection
.copyMethod(findMatchingMethod(getReflectionData().getDeclaredMethods(),
methodName, argumentTypes));
}
public Method[] getDeclaredMethods() {
checkMemberAccess(Member.DECLARED);
return Reflection.copyMethods(getReflectionData().getDeclaredMethods());
}
public Class<?> getDeclaringClass() {
return VMClassRegistry.getDeclaringClass(this);
}
public Field getField(String fieldName) throws NoSuchFieldException {
checkMemberAccess(Member.PUBLIC);
final Field[] fields = getReflectionData().getPublicFields();
for (Field f : fields) {
if (fieldName.equals(f.getName())) {
return Reflection.copyField(f);
}
}
throw new NoSuchFieldException(fieldName.toString());
}
public Field[] getFields() {
checkMemberAccess(Member.PUBLIC);
return Reflection.copyFields(getReflectionData().getPublicFields());
}
@SuppressWarnings("unchecked")
public Class[] getInterfaces() {
return VMClassRegistry.getInterfaces(this);
}
@SuppressWarnings("unchecked")
public Method getMethod(String methodName, Class... argumentTypes)
throws NoSuchMethodException {
checkMemberAccess(Member.PUBLIC);
return Reflection
.copyMethod(findMatchingMethod(getReflectionData().getPublicMethods(),
methodName, argumentTypes));
}
public Method[] getMethods() {
checkMemberAccess(Member.PUBLIC);
return Reflection.copyMethods(getReflectionData().getPublicMethods());
}
public int getModifiers() {
return getReflectionData().getModifiers();
}
public String getName() {
return getReflectionData().name;
}
public Package getPackage() {
ClassLoader classLoader = getClassLoaderImpl();
return classLoader == null
? ClassLoader.BootstrapLoader.getPackage(getPackageName())
: classLoader.getPackage(getPackageName());
}
public ProtectionDomain getProtectionDomain() {
SecurityManager sc = System.getSecurityManager();
if (sc != null) {
sc.checkPermission(
RuntimePermissionCollection.GET_PROTECTION_DOMAIN_PERMISSION);
}
if (domain == null) {
if (systemDomain == null) {
Permissions allPermissions = new Permissions();
allPermissions.add(new AllPermission());
systemDomain = new ProtectionDomain(null, allPermissions);
}
return systemDomain;
}
return domain;
}
public URL getResource(String resource) {
resource = getAbsoluteResource(resource);
ClassLoader classLoader = getClassLoaderImpl();
return classLoader == null
? ClassLoader.getSystemResource(resource)
: classLoader.getResource(resource);
}
public InputStream getResourceAsStream(String resource) {
resource = getAbsoluteResource(resource);
ClassLoader classLoader = getClassLoaderImpl();
return classLoader == null
? ClassLoader.getSystemResourceAsStream(resource)
: classLoader.getResourceAsStream(resource);
}
public Object[] getSigners() {
try {
Object[] signers = (Object[])getClassLoaderImpl().classSigners.get(getName());
return (Object[])signers.clone();
} catch (NullPointerException e) {
}
try {
return (Object[])domain.getCodeSource().getCertificates().clone();
} catch (NullPointerException e) {
}
return null;
}
public Class<? super T> getSuperclass() {
return VMClassRegistry.getSuperclass(this);
}
public boolean isArray() {
return getReflectionData().isArray;
}
public boolean isAssignableFrom(Class<?> clazz) {
if (SERIALIZABLE_CLASS.equals(this)) {
return clazz.getReflectionData().isSerializable();
}
if (EXTERNALIZABLE_CLASS.equals(this)) {
return clazz.getReflectionData().isExternalizable();
}
return VMClassRegistry.isAssignableFrom(this, clazz);
}
public boolean isInstance(Object obj) {
return VMClassRegistry.isInstance(this, obj);
}
public boolean isInterface() {
return (getModifiers() & ACC_INTERFACE) != 0;
}
public boolean isPrimitive() {
return getReflectionData().isPrimitive;
}
public T newInstance() throws InstantiationException,
IllegalAccessException {
T newInstance = null;
final ReflectionData localReflectionData = getReflectionData();
SecurityManager sc = System.getSecurityManager();
if (sc != null) {
sc.checkMemberAccess(this, Member.PUBLIC);
sc.checkPackageAccess(localReflectionData.packageName);
}
/*
* HARMONY-1930: The synchronization issue is possible here.
*
* The issues is caused by fact that:
* - first thread starts defaultConstructor initialization, including
* setting "isAccessible" flag to "true" for Constrcutor object
* - another thread bypasses initialization and calls "newInstance"
* for defaultConstructor (while isAccessible is "false" yet)
* - so, for this "another" thread the Constructor.newInstance checks
* the access rights by mistake and IllegalAccessException happens
*/
while (!isDefaultConstructorInitialized) {
synchronized (localReflectionData) {
if (isDefaultConstructorInitialized) {
break; // non-first threads can be here - nothing to do
}
// only first thread can reach this point & do initialization
final Constructor<T> c;
try {
c = localReflectionData.getDefaultConstructor();
} catch (NoSuchMethodException e) {
throw new InstantiationException(e.getMessage()
+ " method not found");
}
try {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
c.setAccessible(true);
return null;
}
});
} catch (SecurityException e) {
// can't change accessibility of the default constructor
IllegalAccessException ex = new IllegalAccessException();
ex.initCause(e);
throw ex;
}
// default constructor is initialized, access flag is set
isDefaultConstructorInitialized = true;
break;
}
}
// initialization is done, threads may work from here in any order
final Constructor<T> defaultConstructor;
try {
defaultConstructor = localReflectionData.getDefaultConstructor();
} catch (NoSuchMethodException e){
throw new AssertionError(e);
}
Reflection.checkMemberAccess(
VMStack.getCallerClass(0),
defaultConstructor.getDeclaringClass(),
defaultConstructor.getDeclaringClass(),
defaultConstructor.getModifiers()
);
try {
newInstance = defaultConstructor.newInstance();
} catch (InvocationTargetException e) {
System.rethrow(e.getCause());
}
return newInstance;
}
@Override
public String toString() {
return isPrimitive() ? getName()
: (isInterface() ? "interface " : "class ") + getName();
}
String getPackageName() {
return getReflectionData().packageName;
}
void setProtectionDomain(ProtectionDomain protectionDomain) {
domain = protectionDomain;
}
private void checkMemberAccess(int accessType) {
SecurityManager sc = System.getSecurityManager();
if (sc != null) {
sc.checkMemberAccess(this, accessType);
sc.checkPackageAccess(getReflectionData().packageName);
}
}
private String getAbsoluteResource(String resource) {
if (resource.startsWith("/")) {
return resource.substring(1);
}
String pkgName = getPackageName();
if (pkgName.length() > 0) {
resource = pkgName.replace('.', '/') + '/' + resource;
}
return resource;
}
private Constructor<T> getDeclaredConstructorInternal(Class<?>[] argumentTypes)
throws NoSuchMethodException {
final Constructor<T>[] declaredConstructors = getReflectionData().getDeclaredConstructors();
for (int i = 0; i < declaredConstructors.length; i++) {
Constructor<T> c = declaredConstructors[i];
if (isTypeMatches(argumentTypes, c.getParameterTypes())) {
return c;
}
}
throw new NoSuchMethodException(getName()
+ printMethodSignature(argumentTypes));
}
private String getTopLevelClassName() {
Class<?> declaringClass = getDeclaringClass();
return declaringClass == null
? getName() : declaringClass.getTopLevelClassName();
}
/**
* VMI method
*/
final ClassLoader getClassLoaderImpl() {
assert(VMClassRegistry.getClassLoader0(this) == definingLoader);
return definingLoader;
}
public Annotation[] getDeclaredAnnotations() {
Annotation[] declared = getCache().getDeclaredAnnotations();
Annotation aa[] = new Annotation[declared.length];
System.arraycopy(declared, 0, aa, 0, declared.length);
return aa;
}
public Annotation[] getAnnotations() {
Annotation[] all = getCache().getAllAnnotations();
Annotation aa[] = new Annotation[all.length];
System.arraycopy(all, 0, aa, 0, all.length);
return aa;
}
@SuppressWarnings("unchecked")
public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {
if(annotationClass == null) {
throw new NullPointerException();
}
for (Annotation aa : getCache().getAllAnnotations()) {
if(annotationClass == aa.annotationType()) {
return (A)aa;
}
}
return null;
}
public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
if(annotationClass == null) {
throw new NullPointerException();
}
for (Annotation aa : getCache().getAllAnnotations()) {
if(annotationClass == aa.annotationType()) {
return true;
}
}
return false;
}
@SuppressWarnings("unchecked")
public T[] getEnumConstants() {
if (isEnum()) {
try {
final Method values = getMethod("values");
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
values.setAccessible(true);
return null;
}
});
return (T[]) values.invoke(null);
} catch (Exception ignore) {}
}
return null;
}
public boolean isEnum() {
// check for superclass is needed for compatibility
// otherwise there are false positives on anonymous element classes
return ((getModifiers() & ACC_ENUM) != 0 && getSuperclass() == ENUM_CLASS);
}
public boolean isAnnotation() {
return (getModifiers() & ACC_ANNOTATION) != 0;
}
@SuppressWarnings("unchecked")
public <U> Class<? extends U> asSubclass(Class<U> clazz) throws ClassCastException {
if (!VMClassRegistry.isAssignableFrom(clazz, this)) {
throw new ClassCastException(toString());
}
return (Class<? extends U>)this;
}
@SuppressWarnings("unchecked")
public T cast(Object obj) throws ClassCastException {
if (obj != null && !VMClassRegistry.isInstance(this, obj)) {
throw new ClassCastException(obj.getClass().toString());
}
return (T) obj;
}
public TypeVariable<Class<T>>[] getTypeParameters() throws GenericSignatureFormatError {
return (TypeVariable<Class<T>>[])getCache().getTypeParameters().clone();
}
public Method getEnclosingMethod() {
Member m = VMClassRegistry.getEnclosingMember(this); // see VMClassRegistry.getEnclosingMember() spec
return m instanceof Method? (Method)m : null;
}
public Constructor<?> getEnclosingConstructor() {
Member m = VMClassRegistry.getEnclosingMember(this); // see VMClassRegistry.getEnclosingMember() spec
return m instanceof Constructor ? (Constructor<?>)m : null;
}
public Type[] getGenericInterfaces() throws GenericSignatureFormatError, TypeNotPresentException, MalformedParameterizedTypeException {
if (isArray()) {
return new Type[]{CLONEABLE_CLASS, SERIALIZABLE_CLASS};
}
if (isPrimitive()) {
return new Type[0];
}
return (Type[])getCache().getGenericInterfaces().clone();
}
public Type getGenericSuperclass() throws GenericSignatureFormatError, TypeNotPresentException, MalformedParameterizedTypeException {
String tmp;
if (isInterface() || ((tmp = getCanonicalName()) != null && tmp.equals("java.lang.Object")) || isPrimitive()) {
return null;
}
if (isArray()) {
return (Type) OBJECT_CLASS;
}
Class<?> clazz = getSuperclass();
if (clazz.getTypeParameters().length == 0) {
return (Type) clazz;
}
return getCache().getGenericSuperclass();
}
public Class<?> getEnclosingClass() {
return VMClassRegistry.getEnclosingClass(this); // see VMClassRegistry.getEnclosingClass() spec
}
public boolean isMemberClass() {
return getDeclaringClass() != null; // see Class.getDeclaringClass() spec
}
public boolean isLocalClass() {
return VMClassRegistry.getEnclosingMember(this) != null && !isAnonymousClass(); // see CFF spec, #4.8.6, first paragraph and VMClassRegistry.getEnclosingMember() spec
}
public boolean isAnonymousClass() {
return getSimpleName().length() == 0;
}
public boolean isSynthetic() {
return (getModifiers() & ACC_SYNTHETIC) != 0;
}
public String getCanonicalName() {
if (isLocalClass() || isAnonymousClass()) {
return null;
}
if (isArray()) {
String res = getComponentType().getCanonicalName();
return res != null ? res + "[]" : null;
}
StringBuffer sb = new StringBuffer(getPackageName());
ArrayList<String> sympleNames = new ArrayList<String>();
Class<?> clss = this;
while ((clss = clss.getDeclaringClass()) != null) {
if (clss.isLocalClass() || clss.isAnonymousClass()) {
return null;
}
sympleNames.add(clss.getSimpleName());
}
if (sb.length() > 0) {
sb.append(".");
}
for (int i = sympleNames.size() - 1; i > -1 ; i--) {
sb.append(sympleNames.get(i)).append(".");
}
sb.append(getSimpleName());
return sb.toString();
}
public String getSimpleName() {
return VMClassRegistry.getSimpleName(this);
}
private final class ReflectionData {
final String packageName;
final String name;
final boolean isPrimitive;
final boolean isArray;
/*
* Do no access the following fields directly from enclosing class;
* use the accessor methods
*/
private volatile int _modifiers;
private volatile Constructor<T>[] _declaredConstructors;
private volatile Field[] _declaredFields;
private volatile Method[] _declaredMethods;
private volatile Constructor<T> _defaultConstructor;
private volatile Constructor<T>[] _publicConstructors;
private volatile Field[] _publicFields;
private volatile Method[] _publicMethods;
private volatile boolean _serialPropsResolved;
private boolean _isExternalizable;
private boolean _isSerializable;
ReflectionData() {
name = VMClassRegistry.getName(Class.this);
isPrimitive = VMClassRegistry.isPrimitive(Class.this);
isArray = VMClassRegistry.isArray(Class.this);
packageName = Class.getParentName(name);
_modifiers = -1;
}
boolean isSerializable(){
resolveSerialProps();
return _isSerializable;
}
boolean isExternalizable() {
resolveSerialProps();
return _isExternalizable;
}
private void resolveSerialProps() {
if (!_serialPropsResolved){
_isExternalizable = VMClassRegistry.isAssignableFrom(EXTERNALIZABLE_CLASS, Class.this);
_isSerializable = VMClassRegistry.isAssignableFrom(SERIALIZABLE_CLASS, Class.this);
_serialPropsResolved = true;
}
}
int getModifiers() {
final int localCopy = _modifiers;
if (localCopy != -1){
return localCopy;
}
return _modifiers = VMClassRegistry.getModifiers(Class.this);
}
Constructor<T>[] getDeclaredConstructors() {
final Constructor<T>[] localCopy = _declaredConstructors;
if (localCopy != null) {
return localCopy;
}
return _declaredConstructors = VMClassRegistry.getDeclaredConstructors(Class.this);
}
Field[] getDeclaredFields() {
final Field[] localCopy = _declaredFields;
if (localCopy == null) {
return _declaredFields = VMClassRegistry
.getDeclaredFields(Class.this);
} else {
return localCopy;
}
}
Method[] getDeclaredMethods() {
final Method[] localCopy = _declaredMethods;
if (localCopy != null) {
return localCopy;
}
return _declaredMethods = VMClassRegistry.getDeclaredMethods(Class.this);
}
Constructor<T> getDefaultConstructor() throws NoSuchMethodException {
final Constructor<T> localCopy = _defaultConstructor;
if (localCopy != null) {
return localCopy;
}
return _defaultConstructor = Class.this.getDeclaredConstructorInternal(null);
}
Constructor<T>[] getPublicConstructors() {
final Constructor<T>[] localCopy = _publicConstructors;
if (localCopy != null) {
return localCopy;
}
final Constructor<T>[] declaredConstructors = getDeclaredConstructors();
ArrayList<Constructor<T>> constructors = new ArrayList<Constructor<T>>(
declaredConstructors.length);
for (int i = 0; i < declaredConstructors.length; i++) {
Constructor<T> c = declaredConstructors[i];
if (Modifier.isPublic(c.getModifiers())) {
constructors.add(c);
}
}
final int size = constructors.size();
@SuppressWarnings("unchecked")
final Constructor<T>[] tempArray = (Constructor<T>[]) new Constructor[size];
return _publicConstructors = constructors.toArray(tempArray);
}
/**
* Stores public fields in order they should be searched by
* getField(name) method.
*/
public synchronized Field[] getPublicFields() {
final Field[] localCopy = _publicFields;
if (localCopy != null) {
return localCopy;
}
final Field[] declaredFields = getDeclaredFields();
// initialize public fields of the super class
int size = declaredFields.length;
Class<?> superClass = Class.this.getSuperclass();
Field[] superFields = null;
if (superClass != null) {
final Class<?>.ReflectionData superClassRefData = superClass.getReflectionData();
superFields = superClassRefData.getPublicFields();
size += superFields.length;
}
// add public fields of this class
Collection<Field> fields = new LinkedHashSet<Field>(size);
for (Field f : declaredFields) {
if (Modifier.isPublic(f.getModifiers())) {
fields.add(f);
}
}
// initialize and add fields of the super interfaces
Class<?>[] interfaces = Class.this.getInterfaces();
for (Class<?> ci : interfaces) {
final Class<?>.ReflectionData ciRefData = ci.getReflectionData();
Field[] fi = ciRefData.getPublicFields();
for (Field f : fi) {
fields.add(f);
}
}
// add public fields of the super class
if (superFields != null) {
for (Field f : superFields) {
if (Modifier.isPublic(f.getModifiers())) {
fields.add(f);
}
}
}
return _publicFields = fields.toArray(new Field[fields.size()]);
}
public synchronized Method[] getPublicMethods() {
final Method[] localCopy = _publicMethods;
if (localCopy != null) {
return localCopy;
}
final Method[] declaredMethods = getDeclaredMethods();
// initialize public methods of the super class
int size = declaredMethods.length;
Class<?> superClass = Class.this.getSuperclass();
Method[] superPublic = null;
if (superClass != null) {
final Class<?>.ReflectionData superClassRefData = superClass.getReflectionData();
superPublic = superClassRefData.getPublicMethods();
size += superPublic.length;
}
// add methods of the super interfaces
Class<?>[] interfaces = Class.this.getInterfaces();
Method[][] intf = null;
if (interfaces.length != 0) {
intf = new Method[interfaces.length][];
for (int i = 0; i < interfaces.length; i++) {
Class<?> ci = interfaces[i];
final Class<?>.ReflectionData ciRefData = ci.getReflectionData();
intf[i] = ciRefData.getPublicMethods();
size += intf[i].length;
}
}
return _publicMethods = Reflection.mergePublicMethods(declaredMethods, superPublic, intf, size);
}
}
private final class GACache {
private Annotation[] allAnnotations;
private Annotation[] declaredAnnotations;
private Type[] genericInterfaces;
private Type genericSuperclass;
private TypeVariable<Class<T>>[] typeParameters;
public synchronized Annotation[] getAllAnnotations() {
if (allAnnotations != null) {
return allAnnotations;
}
if (declaredAnnotations == null) {
declaredAnnotations = VMGenericsAndAnnotations
.getDeclaredAnnotations(Class.this);
}
// look for inherited annotations
Class<?> superClass = Class.this.getSuperclass();
if (superClass != null) {
Annotation[] sa = superClass.getCache().getAllAnnotations();
if (sa.length != 0) {
final int size = declaredAnnotations.length;
Annotation[] all = new Annotation[size + sa.length];
System.arraycopy(declaredAnnotations, 0, all, 0, size);
int pos = size;
next: for (Annotation s : sa) {
if (s.annotationType().isAnnotationPresent(INHERITED_CLASS)) {
for (int i = 0; i < size; i++) {
if (all[i].annotationType() == s.annotationType()) {
// overriden by declared annotation
continue next;
}
}
all[pos++] = s;
}
}
allAnnotations = new Annotation[pos];
System.arraycopy(all, 0, allAnnotations, 0, pos);
return allAnnotations;
}
}
return allAnnotations = declaredAnnotations;
}
public Annotation[] getDeclaredAnnotations() {
if (declaredAnnotations == null) {
declaredAnnotations = VMGenericsAndAnnotations
.getDeclaredAnnotations(Class.this);
}
return declaredAnnotations;
}
public synchronized Type[] getGenericInterfaces() {
if (genericInterfaces == null) {
genericInterfaces = Parser.getGenericInterfaces(Class.this, VMGenericsAndAnnotations.getSignature(Class.this));
}
return genericInterfaces;
}
public Type getGenericSuperclass() {
//So, here it can be only ParameterizedType or ordinary reference class type
if (genericSuperclass == null) {
genericSuperclass = Parser.getGenericSuperClass(Class.this, VMGenericsAndAnnotations.getSignature(Class.this));
}
return genericSuperclass;
}
@SuppressWarnings("unchecked")
public synchronized TypeVariable<Class<T>>[] getTypeParameters() {
if(typeParameters == null){
typeParameters = Parser.getTypeParameters(Class.this,
VMGenericsAndAnnotations.getSignature(Class.this));
}
return typeParameters;
}
}
}