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

org.yestech.lib.lang.Clazz Maven / Gradle / Ivy

Go to download

A collection of classes that can be used across yestech artifacts/components, but must not be dependant on any yestech component. Most of the code is utility type code. When more than a few classes are found to be in a package or the package start to handle more that a few reposibilities then a new independant component is created and the existing code in yeslib is ported to the new component.

There is a newer version: 1.2.0
Show newest version
/*
 * Copyright LGPL3
 * YES Technology Association
 * http://yestech.org
 *
 * http://www.opensource.org/licenses/lgpl-3.0.html
 */

package org.yestech.lib.lang;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Method;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.ArrayList;
import java.io.Serializable;

/**
 * Utility Class for Dealing with {@link Class} and Reflection.
 *
 */
final public class Clazz {
    final private static Logger logger = LoggerFactory.getLogger(Clazz.class);

    private Clazz() {
        super();
    }


    /**
     * Looks up and retrieves an Initialized class.  This means that the
     * class with only load it's static block!
     *
     * @param classFqn FQN of the class to initialize
     * @return The initialized Class
     * @throws RuntimeException If error happens Loading or Initializing
     */
    public static Class getClass(String classFqn) {
        Class clazz = InMemoryReflectionCache.getClass(classFqn);
        return clazz;
    }

    /**
     * Instantiates a Class from a Fully Qualified Name.  It assumes that there
     * is a default Constructor.
     *
     * @param classFQN FQN of the class to Instantiate
     * @return The Instantiated Class
     * @throws RuntimeException If error happens Instantiating
     */
    @SuppressWarnings("unchecked")
    public static  I instantiateClass(String classFQN) {
        return (I)instantiateClass(getClass(classFQN));
    }

    /**
     * Instantiates a Class from a Class.  It assumes that there
     * is a default Constructor.
     *
     * @param clazz Class to Instantiate
     * @return The Instantiated Class
     * @throws RuntimeException If error happens Instantiating
     */
    @SuppressWarnings("unchecked")
    public static  I instantiateClass(Class clazz) {
        try {
            return (I)clazz.newInstance();
        } catch (Exception e) {
            logger.error("Error Instantiating Class: " + clazz, e);
            throw new RuntimeException("Error Instantiating Class: " + clazz, e);
        }
    }

    /**
     * Returns the Method that is a associated with the FQN class.
     *
     * @param classFQN The FQN of the class method is a member of
     * @param methodName The method name
     * @param params Array of Class the are in the method parameter list
     * @return the {@link Method} found
     * @throws RuntimeException If error happens Loading Method
     */
    public static Method getMethod(String classFQN, String methodName, Class[] params) {
        return InMemoryReflectionCache.getMethod(classFQN, methodName, params);
    }

    /**
     * Dynamically invokes a method using the supplied params as the parameters for the call.
     * If the method being invoked is static, the instance should be null.
     *
     * @param method Method to invoke
     * @param methodArgs Parameters that will be passed to the method
     * @param instance Instance of the Onject to invoke method on.  (null if method is static)
     * @return The result of the method call
     * @throws RuntimeException If error happens Invoking Method
     */
    public static Object invoke(Method method, Object[] methodArgs, Object instance) {
        try {
            return method.invoke(instance, methodArgs);
        } catch (Exception e) {
            logger.error("Error Invoking Method: " + method.getName(), e);
            throw new RuntimeException("Error Invoking Method: " + method.getName(), e);
        }
    }

    /**
     * Dynamically invokes a method using the supplied params as the parameters for the call.
     * If the method being invoked is static, the instance should be null.
     *
     * @param classFQN The FQN of the class method is a member of
     * @param methodName The method name
     * @param params Array of Class the are in the method parameter list
     * @param methodArgs Parameters that will be passed to the method
     * @param instance Instance of the Onject to invoke method on.  (null if method is static)
     * @return The result of the method call
     * @throws RuntimeException If error happens Invoking Method
     */
    public static Object invoke(String classFQN, String methodName, Class[] params,
                                Object[] methodArgs, Object instance) {
        return invoke(getMethod(classFQN, methodName, params), methodArgs, instance);
    }

    /**
     * Returns a Cached Method associated by the methodName.  If the method
     * isn't in the cache a new one is created and added to the cache.  There
     * will ALWAYS be only one method instance in the cache.
     *
     * @param clazz      Class method associated with
     * @param methodName Name of the method
     * @param argTypes   Class Array of argument types in method signature
     * @return The Method
     */
    public static Method getMethod(Class clazz, String methodName, Class[] argTypes) {
        return InMemoryReflectionCache.getMethod(clazz, methodName, argTypes);
    }

    /**
     * Returns a Cached Constructor associated with the Class.  If the
     * Constructor isn't in the cache a new one is created and added to the
     * cache.  There will ALWAYS be only one Constructor instance in the
     * cache.
     *
     * @param clazz     Class Constructor associated with
     * @param ctorTypes Class Array of argument types in Constructors signature
     * @return The Constructor
     */
    public static Constructor getConstructor(Class clazz, Class[] ctorTypes) {
        return InMemoryReflectionCache.getCtor(clazz, ctorTypes);
    }

    /**
     * This class represents the manager for all the different cache policies.
     *
     * @author Arthur Copeland
     */
    private static class InMemoryReflectionCache implements Serializable {

        //--------------------------------------------------------------------------
        // C L A S S   V A R I A B L E S
        //--------------------------------------------------------------------------
        final private static Logger logger = LoggerFactory.getLogger(InMemoryReflectionCache.class);

        final private static HashMap classCache = new HashMap();

        final private static HashMap methodCache = new HashMap();

        final private static HashMap ctorCache = new HashMap();


        //--------------------------------------------------------------------------
        // S T A T I C   I N I T I A L I Z E R
        //--------------------------------------------------------------------------

        //--------------------------------------------------------------------------
        // C O N S T R U C T O R S
        //--------------------------------------------------------------------------

        /**
         * default ctor
         */
        private InMemoryReflectionCache() {
            super();
        }

        //--------------------------------------------------------------------------
        // S T A T I C   M E T H O D S
        //--------------------------------------------------------------------------
        /**
         * Returns a Cached Initialized Class associated by the className.  If the
         * class isn't in the cache a new one is created, initialized and added to
         * the cache.  There will ALWAYS be only one class instance in the
         * cache.
         *
         * @param className FQN of Class to find and initialize
         * @return The Class
         */
        public static Class getClass(String className) {
            Class clazz = classCache.get(className);
            if (clazz == null) {
                try {
                    clazz = Class.forName(className);
                } catch (ClassNotFoundException e) {
                    logger.error(e.getMessage(), e);
                    throw new RuntimeException(e);
                }
                classCache.put(className, clazz);
            }

            return clazz;
        }

        /**
         * Returns a Cached Method associated by the methodName.  If the method
         * isn't in the cache a new one is created and added to the cache.  There
         * will ALWAYS be only one method instance in the cache.
         *
         * @param clazzName  FQN of Class method associated with
         * @param methodName Name of the method
         * @param argTypes   Class Array of argument types in method signature
         * @return The Method
         */
        public static Method getMethod(String clazzName, String methodName,
                                       Class[] argTypes) {
            return getMethod(getClass(clazzName), methodName, argTypes);
        }

        /**
         * Returns a Cached Method associated by the methodName.  If the method
         * isn't in the cache a new one is created and added to the cache.  There
         * will ALWAYS be only one method instance in the cache.
         *
         * @param clazz      Class method associated with
         * @param methodName Name of the method
         * @param argTypes   Class Array of argument types in method signature
         * @return The Method
         */
        public static Method getMethod(Class clazz, String methodName,
                                       Class[] argTypes) {

            Method method = null;
            ArrayList methods = null;
            methods = methodCache.get(methodName);
            if (methods == null) {
                synchronized (methodCache) {
                    methods = methodCache.get(methodName);
                    if (methods == null) {
                        methods = new ArrayList();
                        methodCache.put(methodName, methods);
                    }
                }
            }
            int sz = methods.size();
            if (sz == 0) {
                try {
                    method = clazz.getMethod(methodName, argTypes);
                } catch (NoSuchMethodException e) {
                    logger.error(e.getMessage(), e);
                    throw new RuntimeException(e);
                }
                synchronized (methods) {
                    if (!methods.contains(method)) {
                        methods.add(method);
                    }
                }
            } else {
                for (int i = 0; i < sz; i++) {
                    Method tmethod = methods.get(i);
                    Class targTypes[] = tmethod.getParameterTypes();
                    if ((argTypes == null || argTypes.length == 0) &&
                            (targTypes == null || targTypes.length == 0)) {
                        method = tmethod;
                    } else {
                        int tsz = targTypes.length;
                        if (argTypes.length == tsz) {
                            //find the first method that satisfies the argTypes!!!!!
                            boolean valid = false;
                            for (int t = 0; t < tsz; t++) {
                                boolean good =
                                        argTypes[t].isAssignableFrom(targTypes[t]);
                                if (!good) {
                                    valid = false;
                                    break;
                                } else {
                                    valid = true;
                                }
                            }
                            if (valid) {
                                method = tmethod;
                            }
                        }
                    }
                }
                if (method == null) {
                    try {
                        method = clazz.getMethod(methodName, argTypes);
                    } catch (NoSuchMethodException e) {
                        logger.error(e.getMessage(), e);
                        throw new RuntimeException(e);
                    }
                    synchronized (methods) {
                        if (!methods.contains(method)) {
                            methods.add(method);
                        }
                    }
                }
            }
            return method;
        }

        /**
         * Returns a Cached Constructor associated with the className.  If the
         * Constructor isn't in the cache a new one is created and added to the
         * cache.  There will ALWAYS be only one Constructor instance in the
         * cache.
         *
         * @param clazzName FQN of Class Constructor associated with
         * @param ctorTypes Class Array of argument types in Constructors signature
         * @return The Constructor
         */
        public static Constructor getCtor(String clazzName, Class[] ctorTypes) {
            return getCtor(getClass(clazzName), ctorTypes);
        }

        /**
         * Returns a Cached Constructor associated with the Class.  If the
         * Constructor isn't in the cache a new one is created and added to the
         * cache.  There will ALWAYS be only one Constructor instance in the
         * cache.
         *
         * @param clazz     Class Constructor associated with
         * @param ctorTypes Class Array of argument types in Constructors signature
         * @return The Constructor
         */
        public static Constructor getCtor(Class clazz, Class[] ctorTypes) {
            String ctorName = clazz.getName();

            Constructor ctor = null;
            ArrayList ctors = null;
            ctors = ctorCache.get(ctorName);
            if (ctors == null) {
                synchronized (ctorCache) {
                    ctors = ctorCache.get(ctorName);
                    if (ctors == null) {
                        ctors = new ArrayList();
                        ctorCache.put(ctorName, ctors);
                    }
                }
            }
            int sz = ctors.size();
            if (sz == 0) {
                try {
                    ctor = clazz.getConstructor(ctorTypes);
                } catch (NoSuchMethodException e) {
                    logger.error(e.getMessage(), e);
                    throw new RuntimeException(e);
                }
                synchronized (ctors) {
                    if (!ctors.contains(ctor)) {
                        ctors.add(ctor);
                    }
                }
            } else {
                for (int i = 0; i < sz; i++) {
                    Constructor tctor = ctors.get(i);
                    Class tctorTypes[] = tctor.getParameterTypes();
                    if ((ctorTypes == null || ctorTypes.length == 0) &&
                            (tctorTypes == null || tctorTypes.length == 0)) {
                        ctor = tctor;
                    } else {
                        int tsz = tctorTypes.length;
                        if (ctorTypes.length == tsz) {
                            //find the first ctor that satisfies the ctorTypes!!!!!
                            boolean valid = false;
                            for (int t = 0; t < tsz; t++) {
                                boolean good =
                                        ctorTypes[t].isAssignableFrom(tctorTypes[t]);
                                if (!good) {
                                    valid = false;
                                    break;
                                } else {
                                    valid = true;
                                }
                            }
                            if (valid) {
                                ctor = tctor;
                            }
                        }
                    }
                }
                if (ctor == null) {
                    try {
                        ctor = clazz.getConstructor(ctorTypes);
                    } catch (NoSuchMethodException e) {
                        logger.error(e.getMessage(), e);
                        throw new RuntimeException(e);
                    }
                    synchronized (ctors) {
                        if (!ctors.contains(ctor)) {
                            ctors.add(ctor);
                        }
                    }
                }
            }
            return ctor;

        }

        //--------------------------------------------------------------------------
        // F A C T O R Y   M E T H O D S
        //--------------------------------------------------------------------------
        /**
         * Returns a CacheManager.
         *
         * @return a CacheManager
         */
        public static InMemoryReflectionCache getManager() {
            return new InMemoryReflectionCache();
        }
    }
}