Classes.java Source code

Java tutorial

Introduction

Here is the source code for Classes.java

Source

/*
 * JBoss, Home of Professional Open Source
 * Copyright 2005, JBoss Inc., and individual contributors as indicated
 * by the @authors tag. See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */

import java.lang.reflect.Array;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.HashMap;
import java.util.Map;

/**
 * A collection of <code>Class</code> utilities.
 * 
 * @version <tt>$Revision: 2787 $</tt>
 * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
 * @author <a href="mailto:scott.stark@jboss.org">Scott Stark</a>
 * @author <a href="mailto:dimitris@jboss.org">Dimitris Andreadis<a/>
 */
@SuppressWarnings("unchecked")
public final class Classes {
    /** The string used to separator packages */
    public static final String PACKAGE_SEPARATOR = ".";

    /** The characther used to separator packages */
    public static final char PACKAGE_SEPARATOR_CHAR = '.';

    /** The default package name. */
    public static final String DEFAULT_PACKAGE_NAME = "<default>";

    /**
     * Describe the class of an object
     * 
     * @param object
     *          the object
     * @return the description
     */
    public static String getDescription(Object object) {
        StringBuffer buffer = new StringBuffer();
        describe(buffer, object);
        return buffer.toString();
    }

    /**
     * Describe the class of an object
     * 
     * @param buffer
     *          the string buffer
     * @param object
     *          the object
     */
    public static void describe(StringBuffer buffer, Object object) {
        if (object == null)
            buffer.append("**null**");
        else
            describe(buffer, object.getClass());
    }

    /**
     * Describe the class
     * 
     * @param buffer
     *          the string buffer
     * @param clazz
     *          the clazz
     */
    public static void describe(StringBuffer buffer, Class clazz) {
        if (clazz == null)
            buffer.append("**null**");
        else {
            buffer.append("{class=").append(clazz.getName());
            Class[] intfs = clazz.getInterfaces();
            if (intfs.length > 0) {
                buffer.append(" intfs=");
                for (int i = 0; i < intfs.length; ++i) {
                    buffer.append(intfs[i].getName());
                    if (i < intfs.length - 1)
                        buffer.append(", ");
                }
            }
            buffer.append("}");
        }
    }

    /**
     * Get the short name of the specified class by striping off the package name.
     * 
     * @param classname
     *          Class name.
     * @return Short class name.
     */
    public static String stripPackageName(final String classname) {
        int idx = classname.lastIndexOf(PACKAGE_SEPARATOR);

        if (idx != -1)
            return classname.substring(idx + 1, classname.length());
        return classname;
    }

    /**
     * Get the short name of the specified class by striping off the package name.
     * 
     * @param type
     *          Class name.
     * @return Short class name.
     */
    public static String stripPackageName(final Class type) {
        return stripPackageName(type.getName());
    }

    /**
     * Get the package name of the specified class.
     * 
     * @param classname
     *          Class name.
     * @return Package name or "" if the classname is in the <i>default</i>
     *         package.
     * 
     * @throws EmptyStringException
     *           Classname is an empty string.
     */
    public static String getPackageName(final String classname) {
        if (classname.length() == 0)
            System.out.println("Empty String Exception");

        int index = classname.lastIndexOf(PACKAGE_SEPARATOR);
        if (index != -1)
            return classname.substring(0, index);
        return "";
    }

    /**
     * Get the package name of the specified class.
     * 
     * @param type
     *          Class.
     * @return Package name.
     */
    public static String getPackageName(final Class type) {
        return getPackageName(type.getName());
    }

    // ///////////////////////////////////////////////////////////////////////
    // Primitives //
    // ///////////////////////////////////////////////////////////////////////

    /** Primitive type name -> class map. */
    private static final Map PRIMITIVE_NAME_TYPE_MAP = new HashMap();

    /** Setup the primitives map. */
    static {
        PRIMITIVE_NAME_TYPE_MAP.put("boolean", Boolean.TYPE);
        PRIMITIVE_NAME_TYPE_MAP.put("byte", Byte.TYPE);
        PRIMITIVE_NAME_TYPE_MAP.put("char", Character.TYPE);
        PRIMITIVE_NAME_TYPE_MAP.put("short", Short.TYPE);
        PRIMITIVE_NAME_TYPE_MAP.put("int", Integer.TYPE);
        PRIMITIVE_NAME_TYPE_MAP.put("long", Long.TYPE);
        PRIMITIVE_NAME_TYPE_MAP.put("float", Float.TYPE);
        PRIMITIVE_NAME_TYPE_MAP.put("double", Double.TYPE);
    }

    /**
     * Get the primitive type for the given primitive name.
     * 
     * <p>
     * For example, "boolean" returns Boolean.TYPE and so on...
     * 
     * @param name
     *          Primitive type name (boolean, int, byte, ...)
     * @return Primitive type or null.
     * 
     * @exception IllegalArgumentException
     *              Type is not a primitive class
     */
    public static Class getPrimitiveTypeForName(final String name) {
        return (Class) PRIMITIVE_NAME_TYPE_MAP.get(name);
    }

    /** Map of primitive types to their wrapper classes */
    private static final Class[] PRIMITIVE_WRAPPER_MAP = { Boolean.TYPE, Boolean.class, Byte.TYPE, Byte.class,
            Character.TYPE, Character.class, Double.TYPE, Double.class, Float.TYPE, Float.class, Integer.TYPE,
            Integer.class, Long.TYPE, Long.class, Short.TYPE, Short.class, };

    /**
     * Get the wrapper class for the given primitive type.
     * 
     * @param type
     *          Primitive class.
     * @return Wrapper class for primitive.
     * 
     * @exception IllegalArgumentException
     *              Type is not a primitive class
     */
    public static Class getPrimitiveWrapper(final Class type) {
        if (!type.isPrimitive()) {
            throw new IllegalArgumentException("type is not a primitive class");
        }

        for (int i = 0; i < PRIMITIVE_WRAPPER_MAP.length; i += 2) {
            if (type.equals(PRIMITIVE_WRAPPER_MAP[i]))
                return PRIMITIVE_WRAPPER_MAP[i + 1];
        }

        // should never get here, if we do then PRIMITIVE_WRAPPER_MAP
        // needs to be updated to include the missing mapping
        System.out.println("Unreachable Statement Exception");
        return null;
    }

    /**
     * Check if the given class is a primitive wrapper class.
     * 
     * @param type
     *          Class to check.
     * @return True if the class is a primitive wrapper.
     */
    public static boolean isPrimitiveWrapper(final Class type) {
        for (int i = 0; i < PRIMITIVE_WRAPPER_MAP.length; i += 2) {
            if (type.equals(PRIMITIVE_WRAPPER_MAP[i + 1])) {
                return true;
            }
        }

        return false;
    }

    /**
     * Check if the given class is a primitive class or a primitive wrapper class.
     * 
     * @param type
     *          Class to check.
     * @return True if the class is a primitive or primitive wrapper.
     */
    public static boolean isPrimitive(final Class type) {
        if (type.isPrimitive() || isPrimitiveWrapper(type)) {
            return true;
        }

        return false;
    }

    /**
     * Check type against boolean, byte, char, short, int, long, float, double.
     * 
     * @param type
     *          The java type name
     * @return true if this is a primative type name.
     */
    public static boolean isPrimitive(final String type) {
        return PRIMITIVE_NAME_TYPE_MAP.containsKey(type);
    }

    /**
     * Instantiate a java class object
     * 
     * @param expected
     *          the expected class type
     * @param property
     *          the system property defining the class
     * @param defaultClassName
     *          the default class name
     * @return the instantiated object
     */
    public static Object instantiate(Class expected, String property, String defaultClassName) {
        String className = getProperty(property, defaultClassName);
        Class clazz = null;
        try {
            clazz = loadClass(className);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException("Cannot load class " + className, e);
        }
        Object result = null;
        try {
            result = clazz.newInstance();
        } catch (InstantiationException e) {
            throw new RuntimeException("Error instantiating " + className, e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException("Error instantiating " + className, e);
        }
        if (expected.isAssignableFrom(clazz) == false)
            throw new RuntimeException("Class " + className + " from classloader " + clazz.getClassLoader()
                    + " is not of the expected class " + expected + " loaded from " + expected.getClassLoader());
        return result;
    }

    // ///////////////////////////////////////////////////////////////////////
    // Class Loading //
    // ///////////////////////////////////////////////////////////////////////

    /**
     * This method acts equivalently to invoking
     * <code>Thread.currentThread().getContextClassLoader().loadClass(className);</code>
     * but it also supports primitive types and array classes of object types or
     * primitive types.
     * 
     * @param className
     *          the qualified name of the class or the name of primitive type or
     *          array in the same format as returned by the
     *          <code>java.lang.Class.getName()</code> method.
     * @return the Class object for the requested className
     * 
     * @throws ClassNotFoundException
     *           when the <code>classLoader</code> can not find the requested
     *           class
     */
    public static Class loadClass(String className) throws ClassNotFoundException {
        return loadClass(className, Thread.currentThread().getContextClassLoader());
    }

    /**
     * This method acts equivalently to invoking classLoader.loadClass(className)
     * but it also supports primitive types and array classes of object types or
     * primitive types.
     * 
     * @param className
     *          the qualified name of the class or the name of primitive type or
     *          array in the same format as returned by the
     *          java.lang.Class.getName() method.
     * @param classLoader
     *          the ClassLoader used to load classes
     * @return the Class object for the requested className
     * 
     * @throws ClassNotFoundException
     *           when the <code>classLoader</code> can not find the requested
     *           class
     */
    public static Class loadClass(String className, ClassLoader classLoader) throws ClassNotFoundException {
        // ClassLoader.loadClass() does not handle primitive types:
        //
        // B byte
        // C char
        // D double
        // F float
        // I int
        // J long
        // S short
        // Z boolean
        // V void
        //
        if (className.length() == 1) {
            char type = className.charAt(0);
            if (type == 'B')
                return Byte.TYPE;
            if (type == 'C')
                return Character.TYPE;
            if (type == 'D')
                return Double.TYPE;
            if (type == 'F')
                return Float.TYPE;
            if (type == 'I')
                return Integer.TYPE;
            if (type == 'J')
                return Long.TYPE;
            if (type == 'S')
                return Short.TYPE;
            if (type == 'Z')
                return Boolean.TYPE;
            if (type == 'V')
                return Void.TYPE;
            // else throw...
            throw new ClassNotFoundException(className);
        }

        // Check for a primative type
        if (isPrimitive(className) == true)
            return (Class) Classes.PRIMITIVE_NAME_TYPE_MAP.get(className);

        // Check for the internal vm format: Lclassname;
        if (className.charAt(0) == 'L' && className.charAt(className.length() - 1) == ';')
            return classLoader.loadClass(className.substring(1, className.length() - 1));

        // first try - be optimistic
        // this will succeed for all non-array classes and array classes that have
        // already been resolved
        //
        try {
            return classLoader.loadClass(className);
        } catch (ClassNotFoundException e) {
            // if it was non-array class then throw it
            if (className.charAt(0) != '[')
                throw e;
        }

        // we are now resolving array class for the first time

        // count opening braces
        int arrayDimension = 0;
        while (className.charAt(arrayDimension) == '[')
            arrayDimension++;

        // resolve component type - use recursion so that we can resolve primitive
        // types also
        Class componentType = loadClass(className.substring(arrayDimension), classLoader);

        // construct array class
        return Array.newInstance(componentType, new int[arrayDimension]).getClass();
    }

    /**
     * Get a system property
     * 
     * @param name
     *          the property name
     * @param defaultValue
     *          the default value
     */
    private static String getProperty(final String name, final String defaultValue) {
        return (String) AccessController.doPrivileged(new PrivilegedAction() {
            public Object run() {
                return System.getProperty(name, defaultValue);
            }
        });
    }
}