edu.brown.utils.ClassUtil.java Source code

Java tutorial

Introduction

Here is the source code for edu.brown.utils.ClassUtil.java

Source

/***************************************************************************
 *  Copyright (C) 2012 by H-Store Project                                  *
 *  Brown University                                                       *
 *  Massachusetts Institute of Technology                                  *
 *  Yale University                                                        *
 *                                                                         *
 *  http://hstore.cs.brown.edu/                                            *
 *                                                                         *
 *  Permission is hereby granted, free of charge, to any person obtaining  *
 *  a copy of this software and associated documentation files (the        *
 *  "Software"), to deal in the Software without restriction, including    *
 *  without limitation the rights to use, copy, modify, merge, publish,    *
 *  distribute, sublicense, and/or sell copies of the Software, and to     *
 *  permit persons to whom the Software is furnished to do so, subject to  *
 *  the following conditions:                                              *
 *                                                                         *
 *  The above copyright notice and this permission notice shall be         *
 *  included in all copies or substantial portions of the Software.        *
 *                                                                         *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        *
 *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     *
 *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
 *  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR      *
 *  OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,  *
 *  ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR  *
 *  OTHER DEALINGS IN THE SOFTWARE.                                        *
 ***************************************************************************/
package edu.brown.utils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.collections15.CollectionUtils;
import org.apache.commons.lang.ClassUtils;
import org.apache.log4j.Logger;

import edu.brown.logging.LoggerUtil;
import edu.brown.logging.LoggerUtil.LoggerBoolean;

/**
 * @author pavlo
 */
public abstract class ClassUtil {
    private static final Logger LOG = Logger.getLogger(ClassUtil.class);
    private static final LoggerBoolean debug = new LoggerBoolean();
    private static final LoggerBoolean trace = new LoggerBoolean();
    static {
        LoggerUtil.attachObserver(LOG, debug, trace);
    }

    private static final Map<Class<?>, List<Class<?>>> CACHE_getSuperClasses = new HashMap<Class<?>, List<Class<?>>>();
    private static final Map<Class<?>, Set<Class<?>>> CACHE_getInterfaceClasses = new HashMap<Class<?>, Set<Class<?>>>();

    /**
     * @param clazz
     * @return
     */
    public static <T> Field[] getFieldsByType(Class<?> clazz, Class<? extends T> fieldType) {
        List<Field> fields = new ArrayList<Field>();
        for (Field f : clazz.getDeclaredFields()) {
            int modifiers = f.getModifiers();
            if (Modifier.isTransient(modifiers) == false && Modifier.isPublic(modifiers) == true
                    && Modifier.isStatic(modifiers) == false
                    && ClassUtil.getSuperClasses(f.getType()).contains(fieldType)) {

                fields.add(f);
            }
        } // FOR
        return (fields.toArray(new Field[fields.size()]));
    }

    /**
     * Returns true if asserts are enabled. This assumes that
     * we're always using the default system ClassLoader
     */
    public static boolean isAssertsEnabled() {
        boolean ret = false;
        try {
            assert (false);
        } catch (AssertionError ex) {
            ret = true;
        }
        return (ret);
    }

    /**
     * Convenience method to get the name of the method that invoked this method
     * This is slow and should not be used for anything other than debugging
     * @return
     */
    public static String getCurrentMethodName() {
        StackTraceElement stack[] = Thread.currentThread().getStackTrace();
        assert (stack[2] != null);
        return String.format("%s.%s", stack[2].getClassName(), stack[2].getMethodName());
    }

    /**
     * Return the stack trace for the location that calls this method.
     * @return
     */
    public static String[] getStackTrace() {
        String ret[] = null;
        try {
            throw new Exception();
        } catch (Exception ex) {
            StackTraceElement stack[] = ex.getStackTrace();
            ret = new String[stack.length - 1];
            for (int i = 1; i < stack.length; i++) {
                ret[i - 1] = stack[i].toString();
            } // FOR
        }
        return (ret);
    }

    /**
     * Check if the given object is an array (primitve or native).
     * http://www.java2s.com/Code/Java/Reflection/Checkifthegivenobjectisanarrayprimitveornative.htm
     * 
     * @param obj
     *            Object to test.
     * @return True of the object is an array.
     */
    public static boolean isArray(final Object obj) {
        return (obj != null ? obj.getClass().isArray() : false);
    }

    public static boolean[] isArray(final Object objs[]) {
        boolean is_array[] = new boolean[objs.length];
        for (int i = 0; i < objs.length; i++) {
            is_array[i] = ClassUtil.isArray(objs[i]);
        } // FOR
        return (is_array);
    }

    /**
     * Convert a Enum array to a Field array This assumes that the name of each
     * Enum element corresponds to a data member in the clas
     * 
     * @param <E>
     * @param clazz
     * @param members
     * @return
     * @throws NoSuchFieldException
     */
    public static <E extends Enum<?>> Field[] getFieldsFromMembersEnum(Class<?> clazz, E members[])
            throws NoSuchFieldException {
        Field fields[] = new Field[members.length];
        for (int i = 0; i < members.length; i++) {
            fields[i] = clazz.getDeclaredField(members[i].name().toLowerCase());
        } // FOR
        return (fields);
    }

    /**
     * Create a mapping from Field handles to their corresponding Annotation
     * @param <A>
     * @param fields
     * @param annotationClass
     * @return
     */
    public static <A extends Annotation> Map<Field, A> getFieldAnnotations(Field fields[],
            Class<A> annotationClass) {
        Map<Field, A> ret = new LinkedHashMap<Field, A>();
        for (Field f : fields) {
            A a = f.getAnnotation(annotationClass);
            if (a != null)
                ret.put(f, a);
        }
        return (ret);
    }

    /**
     * Get the generic types for the given field
     * 
     * @param field
     * @return
     */
    public static List<Class<?>> getGenericTypes(Field field) {
        ArrayList<Class<?>> generic_classes = new ArrayList<Class<?>>();
        Type gtype = field.getGenericType();
        if (gtype instanceof ParameterizedType) {
            ParameterizedType ptype = (ParameterizedType) gtype;
            getGenericTypesImpl(ptype, generic_classes);
        }
        return (generic_classes);
    }

    private static void getGenericTypesImpl(ParameterizedType ptype, List<Class<?>> classes) {
        // list the actual type arguments
        for (Type t : ptype.getActualTypeArguments()) {
            if (t instanceof Class<?>) {
                // System.err.println("C: " + t);
                classes.add((Class<?>) t);
            } else if (t instanceof ParameterizedType) {
                ParameterizedType next = (ParameterizedType) t;
                // System.err.println("PT: " + next);
                classes.add((Class<?>) next.getRawType());
                getGenericTypesImpl(next, classes);
            }
        } // FOR
        return;
    }

    /**
     * Return an ordered list of all the sub-classes for a given class Useful
     * when dealing with generics
     * 
     * @param element_class
     * @return
     */
    public static List<Class<?>> getSuperClasses(Class<?> element_class) {
        List<Class<?>> ret = ClassUtil.CACHE_getSuperClasses.get(element_class);
        if (ret == null) {
            ret = new ArrayList<Class<?>>();
            while (element_class != null) {
                ret.add(element_class);
                element_class = element_class.getSuperclass();
            } // WHILE
            ret = Collections.unmodifiableList(ret);
            ClassUtil.CACHE_getSuperClasses.put(element_class, ret);
        }
        return (ret);
    }

    /**
     * Get a set of all of the interfaces that the element_class implements
     * 
     * @param element_class
     * @return
     */
    @SuppressWarnings("unchecked")
    public static Collection<Class<?>> getInterfaces(Class<?> element_class) {
        Set<Class<?>> ret = ClassUtil.CACHE_getInterfaceClasses.get(element_class);
        if (ret == null) {
            // ret = new HashSet<Class<?>>();
            // Queue<Class<?>> queue = new LinkedList<Class<?>>();
            // queue.add(element_class);
            // while (!queue.isEmpty()) {
            // Class<?> current = queue.poll();
            // for (Class<?> i : current.getInterfaces()) {
            // ret.add(i);
            // queue.add(i);
            // } // FOR
            // } // WHILE
            ret = new HashSet<Class<?>>(ClassUtils.getAllInterfaces(element_class));
            if (element_class.isInterface())
                ret.add(element_class);
            ret = Collections.unmodifiableSet(ret);
            ClassUtil.CACHE_getInterfaceClasses.put(element_class, ret);
        }
        return (ret);
    }

    @SuppressWarnings("unchecked")
    public static <T> T newInstance(String class_name, Object params[], Class<?> classes[]) {
        return ((T) ClassUtil.newInstance(ClassUtil.getClass(class_name), params, classes));
    }

    public static <T> T newInstance(Class<T> target_class, Object params[], Class<?> classes[]) {
        // Class<?> const_params[] = new Class<?>[params.length];
        // for (int i = 0; i < params.length; i++) {
        // const_params[i] = params[i].getClass();
        // System.err.println("[" + i + "] " + params[i] + " " +
        // params[i].getClass());
        // } // FOR

        Constructor<T> constructor = ClassUtil.getConstructor(target_class, classes);
        T ret = null;
        try {
            ret = constructor.newInstance(params);
        } catch (Exception ex) {
            throw new RuntimeException("Failed to create new instance of " + target_class.getSimpleName(), ex);
        }
        return (ret);
    }

    /**
     * Grab the constructor for the given target class with the provided input parameters.
     * This method will first try to find an exact match for the parameters, and if that
     * fails then it will be smart and try to find one with the input parameters super classes. 
     * @param <T>
     * @param target_class
     * @param params
     * @return
     */
    @SuppressWarnings("unchecked")
    public static <T> Constructor<T> getConstructor(Class<T> target_class, Class<?>... params) {
        NoSuchMethodException error = null;
        try {
            return (target_class.getConstructor(params));
        } catch (NoSuchMethodException ex) {
            // The first time we get this it can be ignored
            // We'll try to be nice and find a match for them
            error = ex;
        }
        assert (error != null);

        if (debug.val) {
            LOG.debug("TARGET CLASS:  " + target_class);
            LOG.debug("TARGET PARAMS: " + Arrays.toString(params));
        }

        final int num_params = (params != null ? params.length : 0);
        List<Class<?>> paramSuper[] = (List<Class<?>>[]) new List[num_params];
        for (int i = 0; i < num_params; i++) {
            paramSuper[i] = ClassUtil.getSuperClasses(params[i]);
            if (debug.val)
                LOG.debug("  SUPER[" + params[i].getSimpleName() + "] => " + paramSuper[i]);
        } // FOR

        for (Constructor<?> c : target_class.getConstructors()) {
            Class<?> cTypes[] = c.getParameterTypes();
            if (debug.val) {
                LOG.debug("CANDIDATE: " + c);
                LOG.debug("CANDIDATE PARAMS: " + Arrays.toString(cTypes));
            }
            if (params.length != cTypes.length)
                continue;

            for (int i = 0; i < num_params; i++) {
                List<Class<?>> cSuper = ClassUtil.getSuperClasses(cTypes[i]);
                if (debug.val)
                    LOG.debug("  SUPER[" + cTypes[i].getSimpleName() + "] => " + cSuper);
                if (CollectionUtils.intersection(paramSuper[i], cSuper).isEmpty() == false) {
                    return ((Constructor<T>) c);
                }
            } // FOR (param)
        } // FOR (constructors)
        throw new RuntimeException("Failed to retrieve constructor for " + target_class.getSimpleName(), error);
    }

    /**
     * @param class_name
     * @return
     */
    public static Class<?> getClass(String class_name) {
        Class<?> target_class = null;
        try {
            ClassLoader loader = ClassLoader.getSystemClassLoader();
            target_class = (Class<?>) loader.loadClass(class_name);
        } catch (Exception ex) {
            throw new RuntimeException("Failed to retrieve class for " + class_name, ex);
        }
        return (target_class);

    }
}