Package java.lang

Source Code of java.lang.Class$ReflectionData

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

Related Classes of java.lang.Class$ReflectionData

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.