ReflectUtils.java Source code

Java tutorial

Introduction

Here is the source code for ReflectUtils.java

Source

import java.lang.reflect.Array;
import java.lang.reflect.Method;

/* 
 * 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.
 *
 */

/**
 * 
 * ReflectUtils is a collection of utilities that allows you to leverage Java
 * reflection without all of the checked exceptions (they are converted to
 * runtime exceptions or return values). This class was created to get around
 * the fact that the classes in java.lang.reflect.* turn every event into an
 * exception, which is often cumbersome or inaccurate.
 * 
 * @author Dan Jemiolo (danj)
 * 
 */

class ReflectUtils {
    //
    // The class loader used by this class
    //
    private static final ClassLoader _DEFAULT_CLASS_LOADER;

    //
    // The class loader used by this class
    //
    private static ReflectUtilHelper _helper = null;

    static {
        //
        // load the default class loader (we need an instance to do so)
        //
        ReflectUtils instance = new ReflectUtils();
        _DEFAULT_CLASS_LOADER = instance.getClass().getClassLoader();
        _helper = null;
    }

    /**
     * 
     * @param className
     *          The qualified name of the class to search for.
     * 
     * @return True if the class is in the JVM's classpath.
     * 
     */
    public static boolean exists(String className) {
        if (_helper != null)
            return _helper.exists(className);

        try {
            Class.forName(className);
            return true;
        }

        catch (ClassNotFoundException error) {
            return false;
        }
    }

    /**
     * 
     * @param className
     *          The qualified name of the class to search for.
     * 
     * @param classLoader
     *          The class loader to use in the class lookup.
     * 
     * @return True if the class is in the JVM's classpath.
     * 
     */
    public static boolean exists(String className, ClassLoader classLoader) {
        try {
            classLoader.loadClass(className);
            return true;
        }

        catch (ClassNotFoundException error) {
            return false;
        }
    }

    /**
     * 
     * @param theClass
     *          A "normal", non-array type.
     * 
     * @return The array version of the given type. For example, if you pass
     *         <em>String.class</em>, you get <em>String[].class</em>. If
     *         you pass <em>int.class</em>, you get <em>int[].class</em>. If
     *         the given class is already an array type, it is returned.
     * 
     * @see #getClassFromArrayClass(Class)
     * 
     */
    public static Class getArrayClassFromClass(Class theClass) {
        if (theClass.isArray())
            return theClass;

        return Array.newInstance(theClass, 0).getClass();
    }

    /**
     * 
     * This method calls getClass(Class, ClassLoader) with this class'
     * ClassLoader.
     * 
     * @param className
     *          The name of the class to load.
     * 
     * @return The Class representing the given class name. A RuntimeException is
     *         thrown if the class is not found.
     * 
     * @see #exists(String)
     * 
     */
    public static Class getClass(String className) {
        if (_helper != null) {
            Class clazz = _helper.getClass(className);

            if (clazz != null)
                return clazz;
        }

        return getClass(className, _DEFAULT_CLASS_LOADER);
    }

    /**
     * 
     * @param className
     *          The name of the class to load.
     * 
     * @param classLoader
     *          The class loader to use for class lookup.
     * 
     * @return The Class representing the given class name. A RuntimeException is
     *         thrown if the class is not found.
     * 
     * @see #exists(String)
     * 
     */
    public static Class getClass(String className, ClassLoader classLoader) {
        try {
            return classLoader.loadClass(className);
        }

        catch (Throwable error) {
            //
            // if it failed, try the default loader, if applicable
            //
            if (_helper != null) {
                Class clzz = _helper.getClass(className);
                if (clzz != null)
                    return clzz;
            }

            if (classLoader != _DEFAULT_CLASS_LOADER) {
                try {
                    return _DEFAULT_CLASS_LOADER.loadClass(className);
                }

                catch (Throwable error2) {
                    //
                    // still failed - ignore this one and throw from the
                    // original error
                    //
                }
            }

            Object[] filler = { className };
            String message = "JavaClassNotFound";
            throw new RuntimeException(message);
        }
    }

    /**
     * 
     * @param arrayClass
     *          The array version of a given type (<em>YourType[].class</em>)
     * 
     * @return The non-array version of the given type. For example, if you pass
     *         <em>String[].class</em>, you get <em>String.class</em>. If
     *         you pass <em>int[].class</em>, you get <em>int.class</em>.
     * 
     * @see #getArrayClassFromClass(Class)
     * 
     */
    public static Class getClassFromArrayClass(Class arrayClass) {
        if (arrayClass == null)
            throw new NullPointerException("NullClass");

        String name = arrayClass.getName();

        //
        // make sure it's an array type
        //
        if (name.charAt(0) != '[') {
            Object[] filler = { name };
            throw new RuntimeException("NotArrayClass");
        }

        if (name.charAt(1) == '[') {
            Object[] filler = { name };
            throw new RuntimeException("NoMultiArrays");
        }

        //
        // the char after the [ signifies the type of the array. these
        // values are documented with java.lang.Class.getName()
        //
        char type = name.charAt(1);

        switch (type) {
        case 'Z':
            return boolean.class;

        case 'B':
            return byte.class;

        case 'C':
            return char.class;

        case 'D':
            return double.class;

        case 'F':
            return float.class;

        case 'I':
            return int.class;

        case 'J':
            return long.class;

        case 'S':
            return short.class;

        case 'L':
            return getClass(name.substring(2, name.length() - 1));

        default:
            Object[] filler = { name, new Character(type) };
            String message = "UnsupportedType";
            throw new RuntimeException(message);
        }
    }

    public static Method getFirstMethod(Class theClass, String name) {
        Method[] methods = theClass.getMethods();

        for (int n = 0; n < methods.length; ++n)
            if (name.equals(methods[n].getName()))
                return methods[n];

        return null;
    }

    /**
     * 
     * @param theClass
     * 
     * @return The full name of the Java package that contains the given class, or
     *         null if the class is not in a package.
     * 
     */
    public static String getPackageName(Class theClass) {
        //
        // NOTE: Using the Package would be the easiest way to get this
        // data, but the ClassLoader is not required to provide it. Thus,
        // we use the more reliable method of parsing the class name.
        //

        //
        // arrays will have the [ as part of their name - no good
        //
        if (theClass.isArray())
            theClass = getClassFromArrayClass(theClass);

        return getPackageName(theClass.getName());
    }

    /**
     * 
     * @param qualifiedName
     * 
     * @return The full name of the Java package that contains the given class, or
     *         null if the class is not in a package.
     * 
     */
    public static String getPackageName(String qualifiedName) {
        int dot = qualifiedName.lastIndexOf('.');
        return dot >= 0 ? qualifiedName.substring(0, dot) : null;
    }

    /**
     * 
     * @param type
     * 
     * @return The unqualified (local) name of the class/interface. If the type is
     *         an array, the [] characters will be appended.
     * 
     */
    public static String getShortName(Class type) {
        if (type.isArray()) {
            Class base = getClassFromArrayClass(type);
            String name = getShortName(base);
            return name + "[]";
        }

        return getShortName(type.getName());
    }

    /**
     * 
     * @param qualifiedName
     * 
     * @return The unqualified (local) name.
     * 
     */
    public static String getShortName(String qualifiedName) {
        int dot = qualifiedName.lastIndexOf('.');
        return qualifiedName.substring(dot + 1);
    }

    /**
     * 
     * Invokes the Class.newInstance() method on the given Class.
     * 
     * @param theClass
     *          The type to instantiate.
     * 
     * @return An object of the given type, created with the default constructor.
     *         A RuntimeException is thrown if the object could not be created.
     * 
     */
    public static Object newInstance(Class theClass) {
        try {
            return theClass.newInstance();
        }

        catch (InstantiationException error) {
            Object[] filler = { theClass };
            String message = "ObjectCreationFailed";
            throw new RuntimeException(message);
        }

        catch (IllegalAccessException error) {
            Object[] filler = { theClass };
            String message = "DefaultConstructorHidden";
            throw new RuntimeException(message);
        }
    }

    /**
     * 
     * This is a convenience method that invokes newInstance(Class) with a Class
     * object representing the given type.
     * 
     * @see #getClass(String, ClassLoader)
     * @see #newInstance(Class)
     * 
     */
    public static Object newInstance(String className) {
        return newInstance(getClass(className));
    }

    /**
     * 
     * This is a convenience method that invokes newInstance(Class) with a Class
     * object loaded by the given ClassLoader
     * 
     * @see #getClass(String, ClassLoader)
     * @see #newInstance(Class)
     * 
     */
    public static Object newInstance(String className, ClassLoader classLoader) {
        return newInstance(getClass(className, classLoader));
    }

    /**
     * 
     * This is a setter for the helper object
     * 
     */
    public static void setHelper(ReflectUtilHelper helper) {
        _helper = helper;
    }
}

/**
 * 
 * @author Joel Hawkins
 * 
 */
interface ReflectUtilHelper {
    boolean exists(String className);

    Class getClass(String className);
}