view graal/com.oracle.max.base/src/com/sun/max/lang/Classes.java @ 4142:bc8527f3071c

Adjust code base to new level of warnings.
author Thomas Wuerthinger <thomas.wuerthinger@oracle.com>
date Sun, 18 Dec 2011 05:24:06 +0100
parents e233f5660da4
children
line wrap: on
line source

/*
 * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
package com.sun.max.lang;

import java.lang.reflect.*;

import com.sun.max.*;

/**
 * Methods that might be members of java.lang.Class.
 */
public final class Classes {

    private Classes() {
    }

    /**
     * Wraps a call to {@link ClassLoader#loadClass(String)} that is expected not to fail. Should a
     * {@link ClassNotFoundException} occur, it is converted to {@link NoClassDefFoundError}
     *
     * @return the value returned by calling {@link ClassLoader#loadClass(String)} on {@code classLoader}
     */
    public static Class load(ClassLoader classLoader, String name) {
        try {
            return classLoader.loadClass(name);
        } catch (ClassNotFoundException e) {
            throw (NoClassDefFoundError) new NoClassDefFoundError(name).initCause(e);
        }
    }

    /**
     * Wraps a call to {@link Class#forName(String)} that is expected not to fail. Should a
     * {@link ClassNotFoundException} occur, it is converted to {@link NoClassDefFoundError}
     */
    public static Class forName(String name) {
        try {
            return Class.forName(name);
        } catch (ClassNotFoundException e) {
            throw (NoClassDefFoundError) new NoClassDefFoundError(name).initCause(e);
        }
    }

    /**
     * Wraps a call to {@link Class#forName(String, boolean, ClassLoader)} that is expected not to fail. Should a
     * {@link ClassNotFoundException} occur, it is converted to {@link NoClassDefFoundError}
     */
    public static Class forName(String name, boolean initialize, ClassLoader loader) {
        try {
            return Class.forName(name, initialize, loader);
        } catch (ClassNotFoundException e) {
            throw (NoClassDefFoundError) new NoClassDefFoundError(name).initCause(e);
        }
    }

    /**
     * Links a given class. If the class {@code c} has already been linked, then this method simply returns. Otherwise,
     * the class is linked as described in the "Execution" chapter of the <a
     * href="http://java.sun.com/docs/books/jls/">Java Language Specification</a>.
     *
     * @param c the class to link
     */
    public static void link(Class c) {
        if (c != null) {
            try {
                final Class<?> linkedClass = Class.forName(c.getName(), false, c.getClassLoader());
                assert linkedClass == c;
            } catch (ClassNotFoundException classNotFoundException) {
                throw (NoClassDefFoundError) new NoClassDefFoundError(c.getName()).initCause(classNotFoundException);
            }
        }
    }

    /**
     * Initializes a given class. If the class {@code c} has already been initialized, then this method simply returns. Otherwise,
     * the class is linked as described in the "Execution" chapter of the <a
     * href="http://java.sun.com/docs/books/jls/">Java Language Specification</a>.
     *
     * @param c the class to link
     */
    public static void initialize(Class c) {
        try {
            Class.forName(c.getName(), true, c.getClassLoader());
        } catch (ClassNotFoundException classNotFoundException) {
            throw (NoClassDefFoundError) new NoClassDefFoundError(c.getName()).initCause(classNotFoundException);
        }
    }

    public static boolean areRelated(Class<?> class1, Class<?> class2) {
        return class1.isAssignableFrom(class2) || class2.isAssignableFrom(class1);
    }

    public static boolean areAssignableFrom(Class<?>[] superTypes, Class<?>... subTypes) {
        if (superTypes.length != subTypes.length) {
            return false;
        }
        for (int i = 0; i < superTypes.length; i++) {
            if (!superTypes[i].isAssignableFrom(subTypes[i])) {
                return false;
            }
        }
        return true;
    }

    /**
     * Extends the functionality of {@link Class#getConstructor(Class...)} to find a constructor whose formal parameter
     * types are assignable from the types of a list of arguments.
     *
     * @param javaClass the class to search in
     * @param arguments the list of arguments that will be passed to the constructor
     * @return the first constructor in {@link Class#getConstructors() javaClass.getConstructors()} that will accept
     *         {@code arguments} or null if no such constructor exists
     */
    public static Constructor<?> findConstructor(Class<?> javaClass, Object... arguments) {
    nextConstructor:
        for (Constructor<?> constructor : javaClass.getConstructors()) {
            final Class<?>[] parameterTypes = constructor.getParameterTypes();
            if (parameterTypes.length == arguments.length) {
                for (int i = 0; i != arguments.length; ++i) {
                    if (!parameterTypes[i].isAssignableFrom(arguments[i].getClass())) {
                        continue nextConstructor;
                    }
                }
                return constructor;
            }
        }
        return null;
    }

    /**
     * Extends the functionality of {@link Class#getMethod(String, Class...)} to find a method whose formal parameter
     * types are assignable from the types of a list of arguments.
     *
     * @param javaClass the class to search in
     * @param name the name of the method to search for
     * @param arguments the list of arguments that will be passed to the constructor
     * @return the first method in {@link Class#getMethods() javaClass.getMethods()} that will accept {@code arguments}
     *         or null if no such method exists
     */
    public static Method findMethod(Class<?> javaClass, String name, Object... arguments) {
    nextMethod:
        for (Method method : javaClass.getMethods()) {
            final Class<?>[] parameterTypes = method.getParameterTypes();
            if (method.getName().equals(name) && parameterTypes.length == arguments.length) {
                for (int i = 0; i != arguments.length; ++i) {
                    if (!parameterTypes[i].isAssignableFrom(arguments[i].getClass())) {
                        continue nextMethod;
                    }
                }
                return method;
            }
        }
        return null;
    }

    /**
     * Extends the functionality of {@link Class#getDeclaredMethod(String, Class...)} to find a method whose formal
     * parameter types are assignable from the types of a list of arguments.
     *
     * @param javaClass the class to search in
     * @param name the name of the method to search for
     * @param arguments the list of arguments that will be passed to the constructor
     * @return the first method in {@link Class#getDeclaredMethods() javaClass.getDeclaredMethods()} that will accept
     *         {@code arguments} or null if no such method exists
     */
    public static Method findDeclaredMethod(Class<?> javaClass, String name, Object... arguments) {
    nextMethod:
        for (Method declaredMethod : javaClass.getDeclaredMethods()) {
            final Class<?>[] parameterTypes = declaredMethod.getParameterTypes();
            if (declaredMethod.getName().equals(name) && parameterTypes.length == arguments.length) {
                for (int i = 0; i != arguments.length; ++i) {
                    if (!parameterTypes[i].isAssignableFrom(arguments[i].getClass())) {
                        continue nextMethod;
                    }
                }
                return declaredMethod;
            }
        }
        return null;
    }

    /**
     * Performs method resolution as detailed in section 5.4.3.3 of the JVM specification except for the accessibility
     * checks detailed in section 5.4.4.
     *
     * @param javaClass the class to start the resolution from
     * @param returnType the return type of the method to resolve
     * @param name the name of the method to resolve
     * @param parameterTypes the parameter types of the method to resolve
     * @return the resolved method
     * @throws NoSuchMethodError if the method resolution fails
     * @throws AbstractMethodError if the resolved method is abstract
     */
    public static Method resolveMethod(Class<?> javaClass, Class returnType, String name, Class... parameterTypes) {
        if (!name.equals("<init>") && !name.equals("<clinit>")) {
            Class<?> declaringClass = javaClass;
            if (javaClass.isInterface()) {
                try {
                    return javaClass.getMethod(name, parameterTypes);
                } catch (NoSuchMethodException e) {
                    throw new NoSuchMethodError(e.getMessage());
                }
            }
            do {
                try {
                    final Method method = getDeclaredMethod(declaringClass, returnType, name, parameterTypes);
                    if (Modifier.isAbstract(method.getModifiers()) && !Modifier.isAbstract(declaringClass.getModifiers())) {
                        throw new AbstractMethodError();
                    }
                    return method;
                } catch (NoSuchMethodError e) {
                    declaringClass = declaringClass.getSuperclass();
                }
            } while (declaringClass != null);
        }
        throw new NoSuchMethodError(returnType.getName() + " " + javaClass.getName() + "." + name + "(" + Utils.toString(parameterTypes, ", ") + ")");
    }

    /**
     * Performs field resolution as detailed in section 5.4.3.2 of the JVM specification except for the accessibility
     * checks detailed in section 5.4.4.
     * @param javaClass the class to start the resolution from
     * @param type the type of the field to resolve
     * @param name the name of the field to resolve
     *
     * @return the resolved field
     * @throws NoSuchFieldError if the field resolution fails
     */
    public static Field resolveField(Class<?> javaClass, Class type, String name) {
        Class<?> declaringClass = javaClass;
        do {
            try {
                return getDeclaredField(declaringClass, name, type);
            } catch (NoSuchFieldError e) {
                for (Class superInterface : javaClass.getInterfaces()) {
                    try {
                        return resolveField(superInterface, type, name);
                    } catch (NoSuchFieldError noSuchFieldError) {
                        // Ignore
                    }
                }
                declaringClass = declaringClass.getSuperclass();
            }
        } while (declaringClass != null);
        throw new NoSuchFieldError(type.getName() + " " + javaClass.getName() + "." + name);
    }

    /**
     * Gets the class or interface that declares the method, field or constructor represented by {@code member}.
     */
    public static Class<?> getDeclaringClass(AccessibleObject member) {
        if (member instanceof Method) {
            final Method method = (Method) member;
            return method.getDeclaringClass();
        }
        if (member instanceof Field) {
            final Field field = (Field) member;
            return field.getDeclaringClass();
        }
        assert member instanceof Constructor;
        final Constructor constructor = (Constructor) member;
        return constructor.getDeclaringClass();
    }

    /**
     * Get hold of a non-public inner class.
     */
    public static Class getInnerClass(Class outerClass, String innerClassSimpleName) {
        for (Class innerClass : outerClass.getDeclaredClasses()) {
            if (innerClass.getSimpleName().equals(innerClassSimpleName)) {
                return innerClass;
            }
        }
        return null;
    }

    /**
     * Extracts a package name from a fully qualified class name.
     *
     * @return "" if {@code className} denotes a class in the unnamed package
     */
    public static String getPackageName(String className) {
        final int index = className.lastIndexOf('.');
        if (index < 0) {
            return "";
        }
        return className.substring(0, index);
    }

    /**
     * Gets the package name for the package of a class.
     *
     * @return "" if {@code c} is a class in the unnamed package
     */
    public static String getPackageName(Class c) {
        return getPackageName(c.getName());
    }

    /**
     * Extracts a simple class name from a fully qualified class name.
     */
    public static String getSimpleName(String className) {
        final int index = className.lastIndexOf('.');
        if (index < 0) {
            return className;
        }
        return className.substring(index + 1);
    }

    /**
     * Extends the functionality of {@link Class#getSimpleName()} to include a non-empty string for anonymous and local
     * classes.
     *
     * @param clazz the class for which the simple name is being requested
     * @param withEnclosingClass specifies if the returned name should be qualified with the name(s) of the enclosing
     *            class/classes of {@code clazz} (if any). This option is ignored if {@code clazz} denotes an anonymous
     *            or local class.
     * @return
     */
    public static String getSimpleName(Class<?> clazz, boolean withEnclosingClass) {
        final String simpleName = clazz.getSimpleName();
        if (simpleName.length() != 0) {
            if (withEnclosingClass) {
                String prefix = "";
                Class enclosingClass = clazz;
                while ((enclosingClass = enclosingClass.getEnclosingClass()) != null) {
                    prefix = prefix + enclosingClass.getSimpleName() + ".";
                }
                return prefix + simpleName;
            }
            return simpleName;
        }
        // Must be an anonymous or local class
        final String name = clazz.getName();
        int index = name.indexOf('$');
        if (index == -1) {
            return name;
        }
        index = name.lastIndexOf('.', index);
        if (index == -1) {
            return name;
        }
        return name.substring(index + 1);
    }

    /**
     * Similar to {@link Class#getDeclaredMethod(String, Class...)} except that
     * the search takes into account the return type.
     */
    public static Method getDeclaredMethod(Class<?> clazz, Class returnType, String name, Class... parameterTypes)  throws NoSuchMethodError {
        for (Method javaMethod : clazz.getDeclaredMethods()) {
            if (javaMethod.getName().equals(name) && javaMethod.getReturnType().equals(returnType)) {
                final Class[] declaredParameterTypes = javaMethod.getParameterTypes();
                if (java.util.Arrays.equals(declaredParameterTypes, parameterTypes)) {
                    return javaMethod;
                }
            }
        }
        throw new NoSuchMethodError(returnType.getName() + " " + clazz.getName() + "." + name + "(" + Utils.toString(parameterTypes, ",") + ")");
    }

    /**
     * A wrapper for a call to {@link Class#getDeclaredMethod(String, Class...)} that must succeed.
     */
    public static Method getDeclaredMethod(Class<?> clazz, String name, Class... parameterTypes) {
        try {
            return clazz.getDeclaredMethod(name, parameterTypes);
        } catch (NoSuchMethodException noSuchMethodException) {
            throw (NoSuchMethodError) new NoSuchMethodError(clazz.getName() + "." + name + "(" + Utils.toString(parameterTypes, ",") + ")").initCause(noSuchMethodException);
        }
    }

    /**
     * A wrapper for a call to {@link Class#getDeclaredConstructor(Class...)} that must succeed.
     */
    public static Constructor getDeclaredConstructor(Class<?> clazz, Class... parameterTypes) {
        try {
            return clazz.getDeclaredConstructor(parameterTypes);
        } catch (NoSuchMethodException noSuchMethodException) {
            throw (NoSuchMethodError) new NoSuchMethodError(clazz.getName() + "(" + Utils.toString(parameterTypes, ",") + ")").initCause(noSuchMethodException);
        }
    }

    /**
     * A wrapper for a call to {@link Class#getDeclaredField(String)} that must succeed.
     */
    public static Field getDeclaredField(Class<?> clazz, String name) {
        try {
            return clazz.getDeclaredField(name);
        } catch (NoSuchFieldException noSuchFieldException) {
            throw (NoSuchFieldError) new NoSuchFieldError(clazz.getName() + "." + name).initCause(noSuchFieldException);
        }
    }

    /**
     * Similar to {@link Class#getDeclaredField(String)} except that the lookup takes into account a given field type.
     */
    public static Field getDeclaredField(Class<?> clazz, String name, Class type) throws NoSuchFieldError {
        for (Field field : clazz.getDeclaredFields()) {
            if (field.getName().equals(name) && field.getType().equals(type)) {
                return field;
            }
        }
        throw new NoSuchFieldError(type.getName() + " " + clazz.getName() + "." + name);
    }

    public static void main(Class<?> classToRun, String[] args) {
        try {
            final Method mainMethod = classToRun.getMethod("main", String[].class);
            mainMethod.invoke(null, (Object) args);
        } catch (Exception e) {
            throw (Error) new Error().initCause(e);
        }
    }

    public static void main(String classToRun, String[] args) {
        main(forName(classToRun), args);
    }

}