org.apache.niolex.commons.reflect.MethodUtil.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.niolex.commons.reflect.MethodUtil.java

Source

/**
 * MethodUtil.java
 *
 * Copyright 2011 Niolex, Inc.
 *
 * Niolex 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.
 */
package org.apache.niolex.commons.reflect;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.reflect.MethodUtils;
import org.apache.niolex.commons.collection.CollectionUtil;

/**
 * MethodUtil is a utility class help programmers call methods reflectively.
 *
 * @author <a href="mailto:xiejiyun@gmail.com">Xie, Jiyun</a>
 * @version 1.0.0
 */
public class MethodUtil {

    /**
     * Retrieve all the types, including class, super classes and interfaces of this object.
     *
     * @param obj the object to be used
     * @return the list contains all the types
     * @throws SecurityException if a security manager is present and the reflection is rejected
     */
    public static final List<Class<?>> getAllTypes(Object obj) {
        return getAllTypes(obj.getClass());
    }

    /**
     * Retrieve all the types, including class, super classes and interfaces of this class.
     *
     * @param clazz the class to be used
     * @return the list contains all the types
     * @throws SecurityException if a security manager is present and the reflection is rejected
     */
    public static final List<Class<?>> getAllTypes(Class<?> clazz) {
        // Store all the classes and interfaces here.
        List<Class<?>> list = new ArrayList<Class<?>>();
        List<Class<?>> interfaces = new ArrayList<Class<?>>();
        // Step 1. Add this class and all the super classes.
        do {
            list.add(clazz);
            CollectionUtil.addAll(interfaces, clazz.getInterfaces());
            clazz = clazz.getSuperclass();
        } while (clazz != null);
        // Step 2. Add all the interfaces.
        HashSet<Class<?>> clsSet = new HashSet<Class<?>>();
        for (int i = 0; i < interfaces.size(); ++i) {
            clazz = interfaces.get(i);
            // Use this hash set to filter duplicates.
            if (clsSet.contains(clazz)) {
                continue;
            }
            clsSet.add(clazz);
            list.add(clazz);
            CollectionUtil.addAll(interfaces, clazz.getInterfaces());
        }
        return list;
    }

    /**
     * Retrieve all the methods including static methods of this class and it's super classes and
     * all of it's interfaces.
     *
     * @param clazz the class to be used
     * @return the list contains all the methods
     * @throws SecurityException if a security manager is present and the reflection is rejected
     * @see #getAllMethods(Class)
     */
    public static final List<Method> getAllMethodsIncludeInterfaces(Class<?> clazz) {
        List<Method> outList = new ArrayList<Method>();
        for (Class<?> type : getAllTypes(clazz)) {
            CollectionUtil.addAll(outList, type.getDeclaredMethods());
        }
        return outList;
    }

    /**
     * Retrieve all the methods including static methods of this class and it's super classes.
     * <p>
     * We don't get methods of interfaces, because every method in a interface must have
     * the real definition in the classes.
     * </p>
     *
     * @param clazz the class to be used
     * @return the list contains all the methods
     * @throws SecurityException if a security manager is present and the reflection is rejected
     * @see #getAllMethodsIncludeInterfaces(Class)
     */
    public static final List<Method> getAllMethods(Class<?> clazz) {
        List<Method> outList = new ArrayList<Method>();
        do {
            CollectionUtil.addAll(outList, clazz.getDeclaredMethods());
            clazz = clazz.getSuperclass();
        } while (clazz != null);
        return outList;
    }

    /**
     * Retrieve all the methods including static methods of this class, neither get super methods nor
     * interface methods.
     *
     * @param clazz the class to be used
     * @return the list contains all the methods including static methods of this class
     * @throws SecurityException if a security manager is present and the reflection is rejected
     * @see #getAllMethods(Class)
     * @see #getAllMethodsIncludeInterfaces(Class)
     */
    public static final List<Method> getThisMethods(Class<?> clazz) {
        List<Method> outList = new ArrayList<Method>();
        CollectionUtil.addAll(outList, clazz.getDeclaredMethods());
        return outList;
    }

    /**
     * The interface used to filter methods.
     *
     * @author <a href="mailto:xiejiyun@foxmail.com">Xie, Jiyun</a>
     * @version 1.0.0
     * @since 2014-1-6
     */
    public static interface Filter {

        /**
         * Test whether we should include interface methods.
         *
         * @return true if include interfaces, false otherwise
         */
        public boolean isIncludeInterfaces();

        /**
         * Test whether we should include super methods.
         *
         * @return true if include super, false otherwise
         */
        public boolean isIncludeSuper();

        /**
         * Test whether this method is valid for return.
         *
         * @param m the method to be tested
         * @return true if valid, false otherwise
         */
        public boolean isValid(Method m);

    }

    /**
     * Retrieve all the methods with the specified filter.
     *
     * @param clazz the class to be used
     * @param filter the filter used to filter methods
     * @return the list contains all the methods which satisfy the filter
     * @throws SecurityException if a security manager is present and the reflection is rejected
     */
    public static final List<Method> getMethods(Class<?> clazz, Filter filter) {
        List<Method> raw = null;
        if (filter.isIncludeInterfaces()) {
            raw = getAllMethodsIncludeInterfaces(clazz);
        } else if (filter.isIncludeSuper()) {
            raw = getAllMethods(clazz);
        } else {
            raw = getThisMethods(clazz);
        }
        List<Method> outList = new ArrayList<Method>();
        for (Method m : raw) {
            if (filter.isValid(m)) {
                outList.add(m);
            }
        }
        return outList;
    }

    /**
     * Retrieve all the methods with the specified method name from this class and
     * all of it's super classes including static methods.
     *
     * @param clazz the class to be used to find methods
     * @param methodName the method name
     * @return the list contains all the methods with this name
     * @throws SecurityException if a security manager is present and the reflection is rejected
     */
    public static final List<Method> getMethods(Class<?> clazz, String methodName) {
        return getMethods(clazz, MethodFilter.create().includeSuper().includeStatic().methodName(methodName));
    }

    /**
     * Get the first found method with the specified method name from this class and
     * all of it's super classes including static methods.
     *
     * @param clazz the class to be used to find methods
     * @param methodName the method name
     * @return the first found method
     * @throws ItemNotFoundException if method not found in this class and all of it's super classes
     */
    public static final Method getFirstMethod(Class<?> clazz, String methodName) {
        List<Method> list = getMethods(clazz, methodName);
        if (list.size() > 0) {
            return list.get(0);
        } else {
            throw new ItemNotFoundException("Method not found.", null);
        }
    }

    /**
     * Get the first found method with the specified method name from the host object including static methods.
     *
     * @param host the host object used to find method
     * @param methodName the method name
     * @return the first found method
     * @throws ItemNotFoundException if method not found in this class and all of it's super classes
     */
    public static final Method getFirstMethod(Object host, String methodName) {
        return getFirstMethod(host.getClass(), methodName);
    }

    /**
     * Retrieve the method with the specified name and parameter types from this class including static method.
     * If this method is not found, we will try to look at it from the super class too.
     *
     * @param clazz the class to be used for reflection
     * @param methodName the method name
     * @param parameterTypes the method parameter types
     * @return the method if found
     * @throws SecurityException if a security manager is present and the reflection is rejected
     * @throws ItemNotFoundException if method not found in this class and all of it's super classes
     */
    public static final Method getMethod(Class<?> clazz, String methodName, Class<?>... parameterTypes) {
        try {
            return clazz.getDeclaredMethod(methodName, parameterTypes);
        } catch (NoSuchMethodException e) {
            clazz = clazz.getSuperclass();
            if (clazz != null) {
                return getMethod(clazz, methodName, parameterTypes);
            } else {
                throw new ItemNotFoundException("Method not found.", e);
            }
        }
    }

    /**
     * Retrieve the methods including static methods with the specified name and parameter types can be
     * assigned from the specified parameter types.
     * <pre>
     * We have mainly two kinds of relax considered here:
     *  1. long <= int <= short (Small type can be relaxed to a larger type for primitives)
     *  2. int <= Integer or Integer <= int (Auto boxing and un-boxing)
     * </pre>
     * <b>Caution! We can not do relax on wrapper types!</b>
     *
     * @param clazz the class to be used for reflection
     * @param methodName the method name
     * @param parameterTypes the parameter types used to call this method
     * @return the list contains all the methods satisfy the condition
     */
    public static final List<Method> getMethodsParamRelax(Class<?> clazz, String methodName,
            Class<?>... parameterTypes) {
        return getMethods(clazz, MethodFilter.create().includeSuper().includeStatic().methodName(methodName)
                .parameterTypes(parameterTypes));
    }

    /**
     * Invoke this method on the specified host object.
     * If it's a static method, the host object could be null.
     *
     * @param host the host object
     * @param m the method to be invoked
     * @param args the parameters used to invoke method
     * @return the result of invoking the method
     * @throws IllegalArgumentException if the arguments are not correct for the method
     * @throws IllegalAccessException if the method can not be accessed
     * @throws InvocationTargetException if exception was thrown from the method
     */
    public static final Object invokeMethod(Object host, Method m, Object... args)
            throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
        m.setAccessible(true);
        return m.invoke(host, args);
    }

    /**
     * Java
     * Invoke the method with this specified method name and arguments on the host. We support
     * auto boxing and primitive relax.
     *
     * @param host ?
     * @param methodName ?
     * @param args ?????
     * @return ?
     * ??? null
     * ?void?null
     * @throws ItemNotFoundException ???????
     * @throws IllegalArgumentException ??
     * @throws IllegalAccessException ??
     * @throws InvocationTargetException ?
     */
    public static final Object invokeMethod(Object host, String methodName, Object... args)
            throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
        if (args == null) {
            args = ArrayUtils.EMPTY_OBJECT_ARRAY;
        }
        int arguments = args.length;
        Class<?>[] parameterTypes = new Class<?>[arguments];
        for (int i = 0; i < arguments; i++) {
            parameterTypes[i] = args[i].getClass();
        }
        return invokeMethod(host, methodName, parameterTypes, args);
    }

    /**
     * Java
     * Invoke the method with this specified method name and arguments on the host. We support
     * auto boxing and primitive relax.
     *
     * @param host ?
     * @param methodName ?
     * @param parameterTypes ??
     * @param args ?????
     * @return ?
     * ??? null
     * ?void?null
     * @throws ItemNotFoundException ???????
     * @throws IllegalArgumentException ??
     * @throws IllegalAccessException ??
     * @throws InvocationTargetException ?
     */
    public static final Object invokeMethod(Object host, String methodName, Class<?>[] parameterTypes,
            Object... args) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
        // Check all methods to find the correct one.
        List<Method> methods = getMethodsParamRelax(host.getClass(), methodName, parameterTypes);
        if (methods.size() > 0) {
            Method m = methods.get(0);
            m.setAccessible(true);
            return m.invoke(host, args);
        }
        throw new ItemNotFoundException("Method not found.", null);
    }

    /**
     * <p>Invoke a named method whose parameter type matches the object type.</p>
     *
     * <p>This method delegates directly to {@link MethodUtils#invokeMethod(Object, String, Object[])}.</p>
     *
     * <p>This method supports calls to methods taking primitive parameters
     * via passing in wrapping classes. So, for example, a <code>Boolean</code> object
     * would match a <code>boolean</code> primitive.</p>
     *
     * <b>This method only work for public/protected/package access methods.</b>
     *
     * @param object invoke method on this object
     * @param methodName get method with this name
     * @param args use these arguments
     * @return The value returned by the invoked method
     *
     * @throws NoSuchMethodException if there is no such accessible method
     * @throws InvocationTargetException wraps an exception thrown by the method invoked
     * @throws IllegalAccessException if the requested method is not accessible via reflection
     *
     * @see #invokeMethod(Object, String, Object...)
     */
    public static Object invokePublicMethod(Object object, String methodName, Object... args)
            throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        return MethodUtils.invokeMethod(object, methodName, args);
    }

}