com.p5solutions.core.utils.ReflectionUtility.java Source code

Java tutorial

Introduction

Here is the source code for com.p5solutions.core.utils.ReflectionUtility.java

Source

/* Pivotal 5 Solutions Inc. - Core Java library for all other Pivotal Java Modules.
 * 
 * Copyright (C) 2011  KASRA RASAEE
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program 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 for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>. 
 */
package com.p5solutions.core.utils;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.Transient;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.support.AopUtils;

/**
 * The Class ReflectionUtility. Consists of static helper methods for use in
 * reflections on java objects / classes
 * 
 * TODO: perhaps amalgamate with spring's reflection utility?
 * 
 * @author Kasra Rasaee
 * 
 */
public class ReflectionUtility {

    /** The cached methods. */
    private static Map<Class<?>, List<Method>> cachedMethods = new HashMap<Class<?>, List<Method>>();

    /** The logger. */
    private static Log logger = LogFactory.getLog(ReflectionUtility.class);

    /**
     * Builds the field name.
     * 
     * @param method
     *          the method
     * @return the string
     */
    public static String buildFieldName(Method method) {
        String fieldName = null;
        String methodName = method.getName();

        if (isGetter(method) || isSet(method)) {
            fieldName = methodName.substring(3);
        } else if (isIs(method)) {
            fieldName = methodName.substring(2);
        }

        fieldName = StringUtils.uncapitalize(fieldName);

        return fieldName;
    }

    /**
     * Builds the setter name.
     * 
     * @param getterMethod
     *          the getter method
     * @return the string
     */
    public static String buildSetterName(Method getterMethod) {
        String name = buildFieldName(getterMethod);
        String firstLetter = name.substring(0, 1).toUpperCase();
        name = "set" + firstLetter + name.substring(1);
        return name;
    }

    /**
     * Builds the getter name.
     * 
     * @param setterMethod
     *          the setter method
     * @return the string
     */
    public static String buildGetterName(Method setterMethod) {
        if (setterMethod != null) {
            Class<?>[] paramTypes = setterMethod.getParameterTypes();

            String fieldName = setterMethod.getName().substring(3);
            if (paramTypes != null && paramTypes.length == 1) {
                if (paramTypes[0].isAssignableFrom(boolean.class)) {
                    return "is" + fieldName;
                }
            } else {
                throw new RuntimeException(
                        "Invalid number of arguments for setter for " + "field name: " + fieldName);
            }

            return "get" + fieldName;
        }

        throw new RuntimeException("Setter method cannot be null");
    }

    /**
     * Find setter method.
     * 
     * @param clazz
     *          the clazz
     * @param getterMethod
     *          the getter method
     * @return the method
     */
    public static Method findSetterMethod(Class<?> clazz, Method getterMethod) {
        if (getterMethod != null) {
            String setterName = buildSetterName(getterMethod);
            if (setterName != null) {
                return findMethod(clazz, setterName, getterMethod.getReturnType());
            }
        }
        return null;
    }

    /**
     * Find setter method.
     * 
     * @param clazz
     *          the clazz
     * @param fieldName
     *          the field name
     * @param paramTypes
     *          the param types
     * @return the method
     */
    public static Method findSetterMethod(Class<?> clazz, String fieldName, Class<?>... paramTypes) {
        String set = "set";
        String firstLetter = fieldName.substring(0, 1).toUpperCase();
        set += firstLetter + fieldName.substring(1);
        return findMethod(clazz, set, paramTypes);
    }

    /**
     * Find setter method ignoring any parameter arguments.
     * 
     * @param clazz
     *          the clazz
     * @param fieldName
     *          the field name
     * @return the method
     */
    public static Method findSetterMethodIgnoreParams(Class<?> clazz, String fieldName) {
        return findSetterMethod(clazz, fieldName, true, (Class<?>[]) null);
    }

    /**
     * Find setter method.
     * 
     * @param clazz
     *          the clazz to search against
     * @param fieldName
     *          the field name to search for
     * @param ignoreParamSearch
     *          ignore parameter search
     * @param paramTypes
     *          the parameter types, note that if ignoreParamSearch is set to
     *          <code>true</code> this field is ignore completely
     * @return the method
     */
    public static Method findSetterMethod(Class<?> clazz, String fieldName, boolean ignoreParamSearch,
            Class<?>... paramTypes) {
        String set = "set";
        String firstLetter = fieldName.substring(0, 1).toUpperCase();
        set += firstLetter + fieldName.substring(1);
        return findMethod(clazz, set, ignoreParamSearch, paramTypes);
    }

    /**
     * Find setter method.
     * 
     * @param clazz
     *          the clazz
     * @param fieldName
     *          the field name
     * @return the method
     */
    public static Method findSetterMethod(Class<?> clazz, String fieldName) {
        return findSetterMethod(clazz, fieldName, (Class<?>[]) null);
    }

    /**
     * Find getter method.
     * 
     * @param clazz
     *          the clazz
     * @param setterMethod
     *          the setter method
     * @return the method
     */
    public static Method findGetterMethod(Class<?> clazz, Method setterMethod) {
        if (setterMethod != null) {
            String getterName = buildGetterName(setterMethod);
            if (getterName != null) {
                return findMethod(clazz, getterName, (Class<?>[]) null);
            }
        }
        return null;
    }

    /**
     * Find getter method.
     * 
     * @param clazz
     *          the clazz
     * @param fieldName
     *          the field name
     * @return the method
     */
    public static Method findGetterMethod(Class<?> clazz, String fieldName) {
        String get = null;

        if (clazz.isAssignableFrom(Boolean.class)) {
            get = "is";
        } else {
            get = "get";
        }

        String firstLetter = fieldName.substring(0, 1).toUpperCase();
        get += firstLetter + fieldName.substring(1);

        return findMethod(clazz, get);
    }

    /**
     * Checks if a method is {@link Transient} either by specifying the transient modifier
     * or the {@link Transient} annotation.
     * 
     * @param method
     *          the method
     * @return true, if is transient
     */
    public static boolean isTransient(Method method) {
        if (Modifier.isTransient(method.getModifiers())) {
            return true;
        }

        if (method.isAnnotationPresent(Transient.class)) {
            return true;
        }

        return false;
    }

    /**
     * Checks if is a {@link Boolean} class.
     * 
     * @param clazz
     *          the clazz
     * @return the boolean
     */
    public static Boolean isBooleanClass(Class<?> clazz) {
        return Boolean.class.isAssignableFrom(clazz);
    }

    /**
     * Checks if is boolean class.
     *
     * @param className the class name
     * @return the boolean
     */
    public static Boolean isBooleanClass(String className) {
        try {
            return isBooleanClass(Class.forName(className));
        } catch (ClassNotFoundException e) {
            return false;
        }
    }

    /**
     * Checks if is {@link Clob}.
     * 
     * @param clazz
     *          the clazz
     * @return the boolean
     */
    public static Boolean isClob(Class<?> clazz) {
        return Clob.class.isAssignableFrom(clazz);
    }

    /**
     * Checks if is {@link Timestamp}.
     * 
     * @param clazz
     *          the clazz
     * @return the boolean
     */
    public static Boolean isTimestamp(Class<?> clazz) {
        return Timestamp.class.isAssignableFrom(clazz);
    }

    /**
     * Checks if is timestamp.
     *
     * @param className the class name
     * @return the boolean
     */
    public static Boolean isTimestamp(String className) {
        try {
            return isTimestamp(Class.forName(className));
        } catch (ClassNotFoundException e) {
            return false;
        }
    }

    /**
     * Checks if is {@link Blob}.
     * 
     * @param clazz
     *          the clazz
     * @return the boolean
     */
    public static Boolean isBlob(Class<?> clazz) {
        return Blob.class.isAssignableFrom(clazz);
    }

    /**
     * Checks if is an {@link InputStream}.
     * 
     * @param clazz
     *          the clazz
     * @return the boolean
     */
    public static Boolean isInputStream(Class<?> clazz) {
        return InputStream.class.isAssignableFrom(clazz);
    }

    /**
     * Checks if is an {@link OutputStream}.
     * 
     * @param clazz
     *          the clazz
     * @return the boolean
     */
    public static Boolean isOutputStream(Class<?> clazz) {
        return OutputStream.class.isAssignableFrom(clazz);
    }

    /**
     * Checks if is {@link Number} .
     * 
     * @param clazz
     *          the clazz
     * @return the boolean
     */
    public static Boolean isNumberClass(Class<?> clazz) {
        return Number.class.isAssignableFrom(clazz);
    }

    /**
     * Checks if is {@link Serializable}.
     * 
     * @param clazz
     *          the clazz
     * @return the boolean
     */
    public static Boolean isSerializableClass(Class<?> clazz) {
        return Serializable.class.isAssignableFrom(clazz);
    }

    /**
     * Checks if is {@link Date}.
     * 
     * @param clazz
     *          the clazz
     * @return the boolean
     */
    public static Boolean isDate(Class<?> clazz) {
        return Date.class.isAssignableFrom(clazz);
    }

    /**
     * Checks if is date.
     *
     * @param className the class name
     * @return the bolean
     */
    public static Boolean isDate(String className) {
        try {
            return isDate(Class.forName(className));
        } catch (ClassNotFoundException e) {
            return false;
        }
    }

    /**
     * Checks if is date or timestamp.
     *
     * @param clazz the clazz
     * @return the boolean
     */
    public static Boolean isDateOrTimestamp(Class<?> clazz) {
        return isDate(clazz) || isTimestamp(clazz);
    }

    /**
     * Checks if is date.
     *
     * @param className the class name
     * @return the bolean
     */
    public static Boolean isDateOrTimestamp(String className) {
        try {
            return isDate(Class.forName(className)) || isTimestamp(className);
        } catch (ClassNotFoundException e) {
            return false;
        }
    }

    /**
     * Checks if is {@link Byte} class.
     * 
     * @param clazz
     *          the clazz
     * @return the boolean
     */
    public static Boolean isByteClass(Class<?> clazz) {
        return Byte.class.isAssignableFrom(clazz);
    }

    /**
     * Checks if is {@link Short} class.
     * 
     * @param clazz
     *          the clazz
     * @return the boolean
     */
    public static Boolean isShortClass(Class<?> clazz) {
        return Short.class.isAssignableFrom(clazz);
    }

    /**
     * Checks if is short class.
     *
     * @param className the class name
     * @return the boolean
     */
    public static Boolean isShortClass(String className) {
        try {
            return isShortClass(Class.forName(className));
        } catch (ClassNotFoundException e) {
            return false;
        }
    }

    /**
     * Checks if is {@link Integer} class.
     * 
     * @param clazz
     *          the clazz
     * @return the boolean
     */
    public static Boolean isIntegerClass(Class<?> clazz) {
        return Integer.class.isAssignableFrom(clazz);
    }

    /**
     * Checks if is integer class.
     *
     * @param className the class name
     * @return the boolean
     */
    public static Boolean isIntegerClass(String className) {
        try {
            return isIntegerClass(Class.forName(className));
        } catch (ClassNotFoundException e) {
            return false;
        }
    }

    /**
     * Checks if is {@link BigInteger} class.
     * 
     * @param clazz
     *          the clazz
     * @return the boolean
     */
    public static Boolean isBigIntegerClass(Class<?> clazz) {
        return BigInteger.class.isAssignableFrom(clazz);
    }

    /**
     * Checks if is big integer class.
     *
     * @param className the class name
     * @return the boolean
     */
    public static Boolean isBigIntegerClass(String className) {
        try {
            return isBigIntegerClass(Class.forName(className));
        } catch (ClassNotFoundException e) {
            return false;
        }
    }

    /**
     * Checks if is {@link Long} class.
     * 
     * @param clazz
     *          the clazz
     * @return the boolean
     */
    public static Boolean isLongClass(Class<?> clazz) {
        return Long.class.isAssignableFrom(clazz);
    }

    /**
     * Checks if is long class.
     *
     * @param className the class name
     * @return the boolean
     */
    public static Boolean isLongClass(String className) {
        try {
            return isLongClass(Class.forName(className));
        } catch (ClassNotFoundException e) {
            return false;
        }
    }

    /**
     * Checks if is {@link Float} class.
     * 
     * @param clazz
     *          the clazz
     * @return the boolean
     */
    public static Boolean isFloatClass(Class<?> clazz) {
        return Float.class.isAssignableFrom(clazz);
    }

    /**
     * Checks if is float class.
     *
     * @param className the class name
     * @return the boolean
     */
    public static Boolean isFloatClass(String className) {
        try {
            return isFloatClass(Class.forName(className));
        } catch (ClassNotFoundException e) {
            return false;
        }
    }

    /**
     * Checks if is {@link Double} class.
     * 
     * @param clazz
     *          the clazz
     * @return the boolean
     */
    public static Boolean isDoubleClass(Class<?> clazz) {
        return Double.class.isAssignableFrom(clazz);
    }

    /**
     * Checks if is double class.
     *
     * @param className the class name
     * @return the boolean
     */
    public static Boolean isDoubleClass(String className) {
        try {
            return isDoubleClass(Class.forName(className));
        } catch (ClassNotFoundException e) {
            return false;
        }
    }

    /**
     * Checks if is {@link BigDecimal} class.
     * 
     * @param clazz
     *          the clazz
     * @return the boolean
     */
    public static Boolean isBigDecimalClass(Class<?> clazz) {
        return BigDecimal.class.isAssignableFrom(clazz);
    }

    /**
     * Checks if is big decimal class.
     *
     * @param className the class name
     * @return the boolean
     */
    public static Boolean isBigDecimalClass(String className) {
        try {
            return isDoubleClass(Class.forName(className));
        } catch (ClassNotFoundException e) {
            return false;
        }
    }

    /**
     * Checks if is natural number class.
     * 
     * @param clazz
     *          the clazz
     * @return the boolean
     */
    public static Boolean isNaturalNumberClass(Class<?> clazz) {
        return isByteClass(clazz) // byte
                || isShortClass(clazz) // short
                || isIntegerClass(clazz) // integer
                || isLongClass(clazz) // long
                || isBigIntegerClass(clazz); // big integer
    }

    /**
     * Checks if is natural number class.
     *
     * @param className the class name
     * @return the boolean
     */
    public static Boolean isNaturalNumberClass(String className) {
        try {
            return isNaturalNumberClass(Class.forName(className));
        } catch (ClassNotFoundException e) {
            return false;
        }
    }

    /**
     * Checks if is decimal number class.
     * 
     * @param clazz
     *          the clazz
     * @return the boolean
     */
    public static Boolean isDecimalNumberClass(Class<?> clazz) {
        return isFloatClass(clazz) // float
                || isDoubleClass(clazz) // double
                || isBigDecimalClass(clazz); // big-decimal
    }

    /**
     * Checks if is string class.
     * 
     * @param clazz
     *          the clazz
     * @return the boolean
     */
    public static Boolean isStringClass(Class<?> clazz) {
        return String.class.isAssignableFrom(clazz);
    }

    // TODO
    public static Boolean isBasicClass(Class<?> clazz) {
        if (clazz != null) {
            if (clazz.isPrimitive()) {
                return true;
            }

            if (isNumberClass(clazz)) {
                return true;
            }

            if (Boolean.class.equals(clazz)) {
                return true;
            }

            // check for char

            if (String.class.equals(clazz)) {
                return true;
            }

            if (isDate(clazz)) {
                return true;
            }

            // TODO check for other types.. such as enums
        }
        return false;
    }

    /**
     * Checks if is map.
     * 
     * @param clazz
     *          the clazz
     * @return the boolean
     */
    public static Boolean isMap(Class<?> clazz) {
        return Map.class.isAssignableFrom(clazz);
    }

    /**
     * Checks if is collection class.
     * 
     * @param clazz
     *          the clazz
     * @return the boolean
     */
    public static Boolean isCollectionClass(Class<?> clazz) {
        return Collection.class.isAssignableFrom(clazz);
    }

    /**
     * Checks if clazz is a map class.
     * 
     * @param clazz
     *          the clazz
     * @return the boolean
     */
    public static Boolean isMapClass(Class<?> clazz) {
        return Map.class.isAssignableFrom(clazz);
    }

    /**
     * Checks if is array.
     * 
     * @param clazz
     *          the clazz
     * @return the boolean
     */
    public static Boolean isArray(Class<?> clazz) {
        return clazz.isArray();
    }

    /**
     * Checks if is array.
     * 
     * @param clazz
     *          the clazz
     * @return the boolean
     */
    public static Boolean isEnum(Class<?> clazz) {
        return clazz.isEnum();
    }

    /**
     * Checks if is byte array.
     * 
     * @param clazz
     *          the clazz
     * @return the boolean
     */
    public static Boolean isByteArray(Class<?> clazz) {
        return byte[].class.isAssignableFrom(clazz);
    }

    /**
     * Check if the method is abstract.
     * 
     * @param method
     * @return
     */
    public static boolean isAbstract(Method method) {
        return Modifier.isAbstract(method.getModifiers());
    }

    /**
     * Is method a getter, such as (getXYZ).
     * 
     * @param method
     *          the method
     * @return true, if checks if is getter
     */
    public static boolean isGetter(Method method) {

        if (method != null) {
            String methodName = method.getName();
            return methodName.startsWith("get");
        }

        return false;
    }

    /**
     * Checks if is checks if is.
     * 
     * @param method
     *          the method
     * @return true, if is checks if is
     */
    public static boolean isIs(Method method) {

        if (method != null) {
            String methodName = method.getName();
            return methodName.startsWith("is");
        }

        return false;
    }

    /**
     * Checks if is sets the.
     * 
     * @param method
     *          the method
     * @return true, if is sets the
     */
    public static boolean isSet(Method method) {
        if (method != null) {
            String methodName = method.getName();
            return methodName.startsWith("set");
        }
        return false;
    }

    /**
     * Gets the value.
     * 
     * @param field
     *          the field
     * @param entity
     *          the entity
     * @return the value
     */
    public static Object getValue(String field, Object entity) {
        Method method = findGetterMethod(entity.getClass(), field);
        return getValue(method, entity);
    }

    /**
     * Gets the value by field.
     * 
     * @param fieldName
     *          the field name
     * @param target
     *          the target
     * @return the value by field
     */
    public static Object getValueByField(String fieldName, Object target) {
        Class<?> clazz = target.getClass();
        Field field = ReflectionUtility.findField(clazz, fieldName);
        return getValue(field, target);
    }

    /**
     * Gets the value.
     * 
     * @param method
     *          the method
     * @param entity
     *          the entity
     * @return the value
     */
    public static Object getValue(Method method, Object entity) {
        try {
            return method.invoke(entity, new Object[] {});
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * Sets the value.
     * 
     * @param method
     *          the method
     * @param entity
     *          the entity
     * @param value
     *          the value
     */
    public static void setValue(Method method, Object entity, Object value) {
        invoke(entity, method, value);
    }

    /**
     * Set value on entity using the field to search for a setter name.
     * 
     * @param field
     *          Field to use when building a setter name
     * @param entity
     *          The entity or target object to set the value on
     * @param value
     *          The actual value being set on the target or entity using the field
     *          name as the base for searching the set method
     */
    public static void setValue(String field, Object entity, Object value) {
        Class<?> clazz = entity.getClass();
        // TODO: why is it ignore-params? ease-of-use?
        Method method = findSetterMethodIgnoreParams(clazz, field);
        // Field field = ReflectionUtility.findField(clazz, fieldName);
        // Class<?>[] fieldSetterParam = new Class[] { field.getClass() };
        // Method method = findSetterMethod(clazz, fieldName, fieldSetterParam);
        if (method != null) {
            setValue(method, entity, value);
        }
    }

    /**
     * Gets the value.
     * 
     * @param field
     *          the field
     * @param target
     *          the target
     * @return the value
     */
    public static Object getValue(Field field, Object target) {
        Object val = null;
        boolean access = field.isAccessible();
        try {
            field.setAccessible(true);
            val = field.get(target);
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            field.setAccessible(access);
        }
        return val;
    }

    /**
     * Sets the value.
     * 
     * @param field
     *          the field
     * @param target
     *          the target
     * @param value
     *          the value
     */
    public static void setValue(Field field, Object target, Object value) {
        try {
            boolean access = field.isAccessible();
            field.setAccessible(true);
            field.set(target, value);
            field.setAccessible(access);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Make accessible.
     * 
     * @param method
     *          the method
     * @return true, if successful
     */
    public static boolean makeAccessible(Method method) {
        boolean original = method.isAccessible();
        if (!original) {
            method.setAccessible(true);
        }
        return original;
    }

    /**
     * Undo accessible.
     * 
     * @param method
     *          the method
     * @param original
     *          the original
     */
    public static void undoAccessible(Method method, boolean original) {
        method.setAccessible(original);
    }

    /**
     * Gets the methods by annotation.
     * 
     * @param <T>
     *          the generic type
     * @param clazz
     *          the clazz
     * @param annotation
     *          the annotation
     * @return the methods by annotation
     */
    public static <T extends Annotation> List<Method> getMethodsByAnnotation(Class<?> clazz, Class<T> annotation) {

        List<Method> methods = new ArrayList<Method>();

        for (Method method : findAllMethods(clazz)) {
            T ann = findAnnotation(method, annotation);

            if (ann != null) {
                methods.add(method);
            }
        }

        return methods;
    }

    /**
     * Checks if is static or final.
     * 
     * @param field
     *          the field
     * @return true, if is static or final
     */
    public static boolean isStaticOrFinal(Field field) {
        return isStatic(field) || isFinal(field);
    }

    /**
     * Checks if is static.
     * 
     * @param field
     *          the field
     * @return true, if is static
     */
    public static boolean isStatic(Field field) {
        int modifiers = field.getModifiers();
        return Modifier.isStatic(modifiers);
    }

    /**
     * Checks if is final.
     * 
     * @param field
     *          the field
     * @return true, if is final
     */
    public static boolean isFinal(Field field) {
        int modifiers = field.getModifiers();
        return Modifier.isFinal(modifiers);
    }

    /**
     * Find field.
     * 
     * @param clazz
     *          the clazz
     * @param fieldName
     *          the field name
     * @return the field
     */
    public static Field findField(Class<?> clazz, String fieldName) {
        return findField(clazz, fieldName, true);
    }

    /**
     * Find field.
     * 
     * @param clazz
     *          the clazz
     * @param fieldName
     *          the field name
     * @param throwException
     *          the throw exception
     * @return the field
     */
    public static Field findField(Class<?> clazz, String fieldName, boolean throwException) {

        Field field = null;
        Class<?> superClazz = clazz.getSuperclass();
        try {
            field = clazz.getDeclaredField(fieldName);
        } catch (Exception e) {
            if (!throwException) {
                logger.error(e);
            }
            if (superClazz.equals(Object.class)) {
                throw new RuntimeException(e);
            }
        }

        if (field == null) {
            field = findField(superClazz, fieldName);
        }

        return field;
    }

    /**
     * Find fields.
     * 
     * @param clazz
     *          the clazz
     * @return the list
     */
    public static List<Field> findFields(Class<?> clazz) {
        List<Field> array = new ArrayList<Field>();
        Field[] fields = clazz.getDeclaredFields();

        // add all the fields within this class
        Collections.addAll(array, fields);

        // check for super classes and fields
        Class<?> superClazz = clazz.getSuperclass();
        if (!superClazz.equals(Object.class)) {
            List<Field> superArray = findFields(superClazz);
            array.addAll(superArray);
        }

        return array;
    }

    /**
     * Find all methods.
     * 
     * @param clazz
     *          the clazz
     * @return the list
     */
    public static List<Method> findAllMethods(Class<?> clazz) {

        List<Method> methods = new ArrayList<Method>();

        // Iterate each method
        for (Method method : clazz.getDeclaredMethods()) {
            methods.add(method);
        }

        // recursively build list of methods
        Class<?> superClazz = clazz.getSuperclass();
        if (superClazz != null) {
            List<Method> superMethods = findAllMethods(superClazz);
            methods.addAll(superMethods);
        }

        return methods;
    }

    /**
     * Find get methods with no params. All getters that aren't Native, Static,
     * Abstract, Synthetic, or Bridge are returned.
     * 
     * @param clazz
     *          the clazz
     * @return the list
     */
    public synchronized static List<Method> findGetMethodsWithNoParams(Class<?> clazz) {

        /* if a cache already exists simply return it */
        List<Method> returnMethods = cachedMethods.get(clazz);

        if (returnMethods == null) {
            /* create a new cache and return it */
            returnMethods = new ArrayList<Method>();

            for (Method method : findAllMethods(clazz)) {

                // check for compiler introduced methods, as well as native methods.
                // simply ignore these methods, as they are probably not what we are
                // looking for.

                int modifiers = method.getModifiers();

                if (Modifier.isNative(modifiers) //
                        || Modifier.isStatic(modifiers) //
                        || Modifier.isAbstract(modifiers) //
                        || method.isSynthetic() //
                        || method.isBridge()) {
                    continue;
                }

                // if its a getter then add it to the list
                if (isIs(method) || isGetter(method)) {
                    if (!doesMethodHaveParams(method)) {
                        returnMethods.add(method);
                    }
                }
            }

            cachedMethods.put(clazz, returnMethods);
        }

        return returnMethods;
    }

    /**
     * Find annotation.
     * 
     * @param <T>
     *          the generic type
     * @param method
     *          the method
     * @param annotation
     *          the annotation
     * @return the t
     */
    public static <T extends Annotation> T findAnnotation(Method method, Class<T> annotation) {
        return method.getAnnotation(annotation);
    }

    /**
     * Find methods with annotation.
     * 
     * aram <T> the generic type
     * 
     * @param clazz
     *          the clazz
     * @param annotation
     *          the annotation
     * @return the a list of objects, otherwise returns empty list
     */
    @SuppressWarnings("unchecked")
    public static <T extends Annotation> List<Method> findMethodsWithAnnotation(Class<?> clazz,
            Class<T> annotation) {
        List<Method> methods = new ArrayList<Method>();
        // find all methods and filter out overridden-s taking only the inner most
        // ones (children)
        // ***won't work***: abstract annotated methods will show up twice but be
        // mapped once w/o annotation... @#^$@#$%#$^
        // Map<String, Method> map = new HashMap<String, Method>();
        // List<Method> allMethods = findAllMethods(clazz); // including super-class
        // for (Method method : allMethods) {
        // String signature = methodSignature(method);
        // if (!map.containsKey(signature)) {
        // map.put(signature, method);
        // }
        // }
        // work off of those methods then
        // List<Method> uniqueMethods = new ArrayList<Method>(map.values());
        // for (Method method : uniqueMethods) { // including super-class
        for (Method method : findAllMethods(clazz)) { // including super-class
            if (hasAnyAnnotation(method, annotation)) {
                methods.add(method);
            }
        }
        // return result
        return methods;
    }

    /**
     * Return type + name + parameter types. Modifiers not included as they can be
     * changed and still be considered as overriding. Example: String_getName(_),
     * void_setPerson(_Person_boolean)
     * 
     * @param method
     * @return
     */
    public static String getMethodSignature(Method method) {
        // return method.toGenericString();
        StringBuilder sb = new StringBuilder(method.getReturnType().getSimpleName()).append("_")
                .append(method.getName()).append("(_");
        for (Class<?> clazz : method.getParameterTypes()) {
            sb.append(clazz.getSimpleName()).append("_");
        }
        sb.append(")");
        return sb.toString();
    }

    /**
     * Find method with annotation.
     * 
     * @param <T>
     *          the generic type
     * @param clazz
     *          the clazz
     * @param annotation
     *          the annotation
     * @return the method
     */
    public static <T extends Annotation> Method findMethodWithAnnotation(Class<?> clazz, Class<T> annotation) {
        List<Method> methods = findMethodsWithAnnotation(clazz, annotation);

        if (methods.size() == 0) {
            throw new RuntimeException(
                    "No methods founds under class type " + clazz + " with an annotation of " + annotation);
        }

        if (methods.size() > 1) {
            throw new RuntimeException(
                    "Too many methods found under class type " + clazz + " with annotation " + annotation);
        }

        return methods.get(0);
    }

    /**
     * Checks for any annotation.
     * 
     * @param method
     *          the method
     * @param clazzAnnotations
     *          the clazz annotations
     * @return true, if successful
     */
    public static boolean hasAnyAnnotation(Method method, Class<? extends Annotation>... clazzAnnotations) {
        for (Class<? extends Annotation> annotation : clazzAnnotations) {
            if (findAnnotation(method, annotation) != null) {
                return true;
            }
        }
        return false;
    }

    /**
     * Checks for any annotation.
     * 
     * @param clazz
     *          the clazz
     * @param clazzAnnotations
     *          the clazz annotations
     * @return true, if successful
     */
    public static boolean hasAnyAnnotation(Class<?> clazz, Class<? extends Annotation>... clazzAnnotations) {
        for (Class<? extends Annotation> annotation : clazzAnnotations) {
            if (findAnnotation(clazz, annotation) != null) {
                return true;
            }
        }
        return false;
    }

    /**
     * Find annotation.
     * 
     * @param <T>
     *          the generic type
     * @param clazz
     *          the clazz
     * @param annotation
     *          the annotation
     * @return the t
     */
    public static <T extends Annotation> T findAnnotation(Class<?> clazz, Class<T> annotation) {
        T ann = clazz.getAnnotation(annotation);
        if (ann == null) {
            Class<?> superClazz = clazz.getSuperclass();
            if (superClazz != null && !superClazz.equals(Object.class)) {
                ann = findAnnotation(superClazz, annotation);
            }
        }
        return ann;
    }

    /**
     * Find method.
     * 
     * @param clazz
     *          the clazz
     * @param methodName
     *          the method name
     * @return the method
     */
    public static Method findMethod(Class<?> clazz, String methodName) {
        return findMethod(clazz, methodName, (Class<?>[]) null);
    }

    /**
     * Find method.
     * 
     * @param clazz
     *          the clazz
     * @param methodName
     *          the method name
     * @param paramTypes
     *          the param types
     * @return the method
     */
    public static Method findMethod(Class<?> clazz, String methodName, Class<?>... paramTypes) {
        return findMethod(clazz, methodName, false, paramTypes);
    }

    /**
     * Check params.
     * 
     * @param method
     *          the method
     * @param paramTypes
     *          the param types
     * @return true, if successful
     */
    public static boolean checkParams(Method method, Class<?>... paramTypes) {

        /* Check the length of parameter types, should be the same */
        Class<?>[] methodParamTypes = method.getParameterTypes();

        // Length of the parameters and method parameters
        int paramTypesLen = 0;
        int methodParamTypesLen = 0;

        // get the parameter length if any
        if (paramTypes != null) {
            methodParamTypesLen = paramTypes.length;
        }

        // get the method parameter length if any
        if (methodParamTypes != null) {
            paramTypesLen = methodParamTypes.length;
        }

        // are the lengths equal?
        if (paramTypesLen != methodParamTypesLen) {
            // if not then return quickly.
            return false;
        }

        // params match yet? no!
        boolean paramsMatch = true;

        /* check to see if parameter types are the same */
        for (int i = 0; i < methodParamTypes.length; i++) {
            /* get the class types for the parameters */
            Class<?> parameterType = paramTypes[i];
            Class<?> methodParamClazz = methodParamTypes[i];

            /* does the parameter match in sequence */
            if (!methodParamClazz.isAssignableFrom(parameterType)) {
                paramsMatch = false;
            }
        }

        /* if all parameter types match then return the method */
        if (paramsMatch) {
            return true;
        }

        return false;
    }

    /**
     * Find method.
     * 
     * @param clazz
     *          the clazz
     * @param methodName
     *          the method name
     * @param ignoreParamSearch
     *          the ignore param search
     * @param paramTypes
     *          the param types
     * @return the method
     */
    public static Method findMethod(Class<?> clazz, String methodName, boolean ignoreParamSearch,
            Class<?>... paramTypes) {

        Method method = null;

        // Iterate all declared methods of the class
        for (Method m : clazz.getDeclaredMethods()) {

            // continue to next method, if name does not match
            if (!m.getName().equals(methodName)) {
                continue;
            }

            // only check the parameter lengths and
            // types if ignoreParamSearch is false
            if (!ignoreParamSearch && checkParams(m, paramTypes)) {
                method = m; // set the returning result
                break; // exit the loop
            } else if (ignoreParamSearch && method != null) {
                throw new RuntimeException(
                        "Multiple methods found, please specify a list of parameter types to refine your method search.");
            }

            method = m;
        }

        /* if the method is still null, then check its superclass */
        if (method == null) {
            Class<?> superClazz = clazz.getSuperclass();

            // if we've hit the base object?
            if (!superClazz.equals(Object.class)) {

                // recursively look for the method
                method = findMethod( //
                        superClazz, //
                        methodName, //
                        ignoreParamSearch, //
                        paramTypes);
            }
        }

        return method;
    }

    /**
     * Does method have params.
     * 
     * @param method
     *          the method
     * @return true, if successful
     */
    public static boolean doesMethodHaveParams(Method method) {
        /* Ignore any getters with parameters */
        if (method.getParameterTypes() != null && method.getParameterTypes().length > 0) {
            return true;
        }

        return false;
    }

    /**
     * Checks if is value null.
     * 
     * @param target
     *          the target
     * @param method
     *          the method
     * @return true, if is value null
     */
    public static boolean isValueNull(Object target, Method method) {
        // get the value of the method
        Object value = ReflectionUtility.invoke(target, method);

        // if its not null then exit with a false
        if (value != null) {
            return false;
        }

        return true;
    }

    /**
     * Invoke.
     * 
     * @param object
     *          the object
     * @param method
     *          the method
     * @return the object
     */
    public static Object invoke(Object object, Method method) {
        return invoke(object, method, (Object[]) null);
    }

    /**
     * Invoke.
     * 
     * @param <O>
     *          the generic type
     * @param <I>
     *          the generic type
     * @param object
     *          the object
     * @param method
     *          the method
     * @param args
     *          the args
     * @return the o
     */
    @SuppressWarnings("unchecked")
    public static <O, I> O invoke(I object, Method method, Object... args) {
        return (O) invokeWithAccessWithArguments(object, method, false, args);
    }

    /**
     * Invoke.
     * 
     * @param <O>
     *          the generic type
     * @param <I>
     *          the generic type
     * @param object
     *          the object
     * @param method
     *          the method
     * @param ignoreAccess
     *          the ignore access
     * @return the o
     */
    @SuppressWarnings("unchecked")
    public static <O, I> O invokeWithAccess(I object, Method method, boolean ignoreAccess) {
        return (O) invokeWithAccessWithArguments(object, method, ignoreAccess, (Object[]) null);
    }

    /**
     * Invoke.
     * 
     * @param <O>
     *          the generic type
     * @param <I>
     *          the generic type
     * @param object
     *          the object
     * @param method
     *          the method
     * @param ignoreAccess
     *          the ignore access
     * @param args
     *          the args
     * @return the object
     */
    @SuppressWarnings("unchecked")
    public static <O, I> O invokeWithAccessWithArguments(I object, Method method, boolean ignoreAccess,
            Object... args) {
        if (object == null) {
            throw new RuntimeException("Object cannot be null when invoking its methods");
        }

        Object returnObject = null;
        Class<?> clazz = object.getClass();

        try {

            /* call the method */
            if (method != null) {
                if (AopUtils.isAopProxy(object)) {
                    InvocationHandler handler = Proxy.getInvocationHandler(object);
                    returnObject = handler.invoke(object, method, args);
                } else {
                    boolean isAccessible = method.isAccessible();
                    try {
                        if (!isAccessible && ignoreAccess) {
                            method.setAccessible(true);
                        }
                        returnObject = method.invoke(object, args);
                    } finally {
                        if (ignoreAccess) {
                            method.setAccessible(isAccessible);
                        }
                    }
                }
            } else {
                throw new RuntimeException("Method cannot be null");
            }
        } catch (Throwable e) {
            // get the target class if its a proxy
            clazz = AopUtils.getTargetClass(object);

            /* Logger that is available to subclasses */
            Log logger = LogFactory.getLog(clazz);
            // logger.error("Unable to invoke method " + method.getName() + " within "
            // + clazz.getCanonicalName() + "\n"
            // + getStackTrace(e));

            throw new RuntimeException(e);
        }

        return (O) returnObject;
    }

    /**
     * Gets the log stack trace.
     * 
     * @param e
     *          the e
     * @return the log stack trace
     */
    public static String getStackTrace(Throwable e) {
        if (e == null) {
            return "";
        }

        ByteArrayOutputStream os = new ByteArrayOutputStream();
        PrintStream ps = new PrintStream(os);
        try {
            e.printStackTrace(ps);
            String ret = os.toString();
            ps.close();
            os.close();
            return ret;
        } catch (IOException t) {
            logger.error("Error in closing the output stream for byte array when getting stack trace on exception "
                    + e.toString());
        }
        return "";
    }

    /**
     * Gets the static value.
     *
     * @param <T> the generic type
     * @param clazz the clazz
     * @param memberName the member name
     * @return the static value
     */
    @SuppressWarnings("unchecked")
    public static <T> T getStaticValue(Class<?> clazz, String memberName) {
        try {
            Field field = clazz.getField(memberName);
            return (T) field.get(null);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * New instance.
     * 
     * @param <T>
     *          the generic type
     * @param clazz
     *          the clazz
     * @return the t
     */
    public static <T> T newInstance(Class<T> clazz) {
        T instance = null;
        try {
            instance = clazz.newInstance();
        } catch (Exception e) {
            logger.error(e);
        }
        return instance;
    }

    /**
     * New instance.
     * 
     * @param <T>
     *          the generic type
     * @param clazz
     *          the clazz
     * @param type
     *          the type
     * @param argument
     *          the argument
     * @return the t
     */
    public static <T> T newInstance(Class<T> clazz, Class<?> type, Object argument) {
        return newInstance(clazz, new Class<?>[] { type }, new Object[] { argument });
    }

    /**
     * New instance.
     * 
     * @param <T>
     *          the generic type
     * @param clazz
     *          the clazz
     * @param paramTypes
     *          the param types
     * @param arguments
     *          the arguments
     * @return the t
     */
    public static <T> T newInstance(Class<T> clazz, Class<?>[] paramTypes, Object[] arguments) {
        T instance = null;

        try {
            // Constructor<?>[] constructors = clazz.getDeclaredConstructors();
            Constructor<T> constructor = clazz.getDeclaredConstructor(paramTypes);
            boolean access = constructor.isAccessible();
            constructor.setAccessible(true);
            instance = constructor.newInstance(arguments);
            if (!access) {
                constructor.setAccessible(false);
            }
        } catch (Exception e) {
            logger.error(e);
        }
        return instance;
    }

    /**
     * Gets the field class.
     * 
     * @param clazz
     *          the class
     * @param fieldName
     *          the field name
     * @return the field class
     */
    public static Class<?> getFieldClass(Class<?> clazz, String fieldName) {

        if (Comparison.isNull(clazz)) {
            // field does not exist
            return null;
        }
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            if (field.getName().equals(fieldName)) {
                // found field return field type
                return field.getType();
            }
        }
        // recursive call to check the super class for field
        return getFieldClass(clazz.getSuperclass(), fieldName);
    }
}