All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ml.shifu.guagua.util.ClassUtils Maven / Gradle / Ivy

The newest version!
/*
 * Copyright [2013-2014] PayPal Software Foundation
 *  
 * Licensed 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 ml.shifu.guagua.util;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * A helper class for java reflection.
 */
public final class ClassUtils {

    private ClassUtils() {
    }

    /**
     * Only support constructors with no parameters.
     */
    public static final Class[] EMPTY_CLASS_ARRAY = new Class[] {};

    /**
     * This map is used for cache  pairs
     */
    private static final Map, Constructor> CONSTRUCTOR_CACHE = new ConcurrentHashMap, Constructor>();

    /**
     * This map is used for cache  pairs
     */
    private static final Map FIELD_CACHE = new ConcurrentHashMap();

    /**
     * This map is used for cache  pairs. Only first method will be cached here, make
     * sure no same method name for such cache.
     */
    private static final Map METHOD_CACHE = new ConcurrentHashMap();

    /**
     * Given a class instance, return all fields, including fields in super classes.
     */
    @SuppressWarnings("unchecked")
    public static List getAllFields(Class clazz) {
        if(clazz == null || clazz.equals(Object.class)) {
            return Collections.EMPTY_LIST;
        }

        List result = new ArrayList();
        for(Field field: clazz.getDeclaredFields()) {
            result.add(field);
        }
        Class tmpClazz = clazz.getSuperclass();
        while(!Object.class.equals(tmpClazz)) {
            result.addAll(getAllFields(tmpClazz));
            tmpClazz = tmpClazz.getSuperclass();
        }

        return result;
    }

    /**
     * Given a class instance, return all methods, including methods in super classes.
     */
    @SuppressWarnings("unchecked")
    public static List getAllMethods(Class clazz) {
        if(clazz == null) {
            return Collections.EMPTY_LIST;
        }

        if(clazz.equals(Object.class)) {
            return Collections.EMPTY_LIST;
        }

        List result = new ArrayList();
        for(Method method: clazz.getDeclaredMethods()) {
            result.add(method);
        }
        Class tmpClazz = clazz.getSuperclass();
        while(!Object.class.equals(tmpClazz)) {
            result.addAll(getAllMethods(tmpClazz));
            tmpClazz = tmpClazz.getSuperclass();
        }

        return result;
    }

    /**
     * Create an object for the given class. The class should have constructor without any parameters.
     * 
     * @param clazz
     *            class of which an object is created
     * @return a new object
     * @throws RuntimeException
     *             In case any exception for reflection.
     */
    public static  T newInstance(Class clazz) {
        T result;
        try {
            @SuppressWarnings("unchecked")
            Constructor meth = (Constructor) CONSTRUCTOR_CACHE.get(clazz);
            if(meth == null) {
                meth = clazz.getDeclaredConstructor(EMPTY_CLASS_ARRAY);
                meth.setAccessible(true);
                CONSTRUCTOR_CACHE.put(clazz, meth);
            }
            result = meth.newInstance();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return result;
    }

    /**
     * Create an object for the given class. The class should have constructor without any parameters.
     * 
     * @param clazz
     *            class of which an object is created
     * @param parameterClasses
     *            the parameter classes used for constructor
     * @param parameters
     *            the parameters used for new instance
     * @return a new object
     * @throws RuntimeException
     *             In case any exception for reflection.
     */
    public static  T newInstance(Class clazz, Class[] parameterClasses, Object[] parameters) {
        T result;
        try {
            @SuppressWarnings("unchecked")
            Constructor meth = (Constructor) CONSTRUCTOR_CACHE.get(clazz);
            if(meth == null) {
                meth = clazz.getDeclaredConstructor(parameterClasses);
                meth.setAccessible(true);
                CONSTRUCTOR_CACHE.put(clazz, meth);
            }
            result = meth.newInstance(parameters);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return result;
    }

    /**
     * Get declared field given field name including fields in super classes. If no field get, return null.
     */
    public static Field getDeclaredFieldIncludeSuper(String fieldName, Class clazz) {
        String key = clazz.getName() + "#" + fieldName;
        Field cacheField = FIELD_CACHE.get(key);
        if(cacheField != null) {
            return cacheField;
        }
        for(Field field: ClassUtils.getAllFields(clazz)) {
            if(field.getName().equals(fieldName)) {
                return field;
            }
        }
        return null;
    }

    /**
     * Return declared method with empty parameter.
     */
    public static Method getDeclaredMethod(String methodName, Class clazz) throws NoSuchMethodException {
        String key = clazz.getName() + "#" + methodName;
        Method cacheMethod = METHOD_CACHE.get(key);
        if(cacheMethod != null) {
            return cacheMethod;
        }
        return clazz.getDeclaredMethod(methodName, ClassUtils.EMPTY_CLASS_ARRAY);
    }

    /**
     * Iterate all methods including methods in super class, return the first one; if no method with such name, return
     * null.
     */
    public static Method getFirstMethodWithName(String name, Class clazz) {
        String key = clazz.getName() + "#" + name;
        Method cacheMethod = METHOD_CACHE.get(key);
        if(cacheMethod != null) {
            return cacheMethod;
        }
        List allMethods = ClassUtils.getAllMethods(clazz);
        Method method = null;
        for(Method f: allMethods) {
            if(f.getName().equals(name)) {
                method = f;
                break;
            }
        }
        return method;
    }

    private static void setFieldValue(Field field, Object instance, Object value) throws IllegalArgumentException,
            IllegalAccessException {
        field.setAccessible(true);
        field.set(instance, value);
    }

    private static Object getFieldValue(Field field, Object instance) throws IllegalArgumentException,
            IllegalAccessException {
        field.setAccessible(true);
        return field.get(instance);
    }

    /**
     * Set filed value according to field name, class instance, object instance and field value. All exceptions are
     * wrapped as RuntimeException.
     * 
     * @throws RuntimeException
     *             wraps any exception as root cause.
     */
    public static void setFieldValue(String fieldName, Class clazz, Object instance, Object value) {
        try {
            Field field = getDeclaredFieldIncludeSuper(fieldName, clazz);
            setFieldValue(field, instance, value);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Return field value according to field name, class, instance.All exceptions are wrapped as RuntimeException.
     * 
     * @throws RuntimeException
     *             wraps any exception as root cause.
     */
    public static Object getFieldValue(String fieldName, Class clazz, Object instance) {
        try {
            Field field = getDeclaredFieldIncludeSuper(fieldName, clazz);
            return getFieldValue(field, instance);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Call method through java reflection.
     * 
     * @throws RuntimeException
     *             wraps any exception as root cause.
     */
    public static Object invokeMethod(Method method, Object instance, Object... parameters) {
        try {
            method.setAccessible(true);
            return method.invoke(instance, parameters);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Call method through java reflection. TODO getFirstMethodWithName should be changed by finding method with method
     * name and parameter types.
     * 
     * @throws RuntimeException
     *             wraps any exception as root cause.
     */
    public static Object invokeMethod(String name, Class clazz, Object instance, Object... parameters) {
        try {
            Method method = getFirstMethodWithName(name, clazz);
            method.setAccessible(true);
            return method.invoke(instance, parameters);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy