Fetches all methods of all access types from the supplied class and super classes : Method « Reflection « Java






Fetches all methods of all access types from the supplied class and super classes

       
import java.util.Map;
import java.util.HashMap;
import java.util.Collection;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.HashSet;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.Queue;
import java.util.LinkedList;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.Arrays;
import java.util.concurrent.ConcurrentHashMap;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

import static java.lang.reflect.Modifier.isPublic;
import java.beans.PropertyDescriptor;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.IntrospectionException;

/**
 * Common utilty methods that are useful when working with reflection.
 *
 * @author Tim Fennell
 */
public class ReflectUtil {
    /** A cache of property descriptors by class and property name */
    private static Map<Class<?>, Map<String, PropertyDescriptor>> propertyDescriptors =
            new ConcurrentHashMap<Class<?>, Map<String, PropertyDescriptor>>();

    /** Static helper class, shouldn't be constructed. */
    private ReflectUtil() {}

    /**
     * Holds a map of commonly used interface types (mostly collections) to a class that
     * implements the interface and will, by default, be instantiated when an instance
     * of the interface is needed.
     */
    protected static final Map<Class<?>,Class<?>> interfaceImplementations = new HashMap<Class<?>,Class<?>>();

    /**
     * Holds a map of primitive type to the default value for that primitive type.  Isn't it
     * odd that there's no way to get this programmatically from the Class objects?
     */
    protected static final Map<Class<?>,Object> primitiveDefaults = new HashMap<Class<?>,Object>();

    static {
        interfaceImplementations.put(Collection.class, ArrayList.class);
        interfaceImplementations.put(List.class,       ArrayList.class);
        interfaceImplementations.put(Set.class,        HashSet.class);
        interfaceImplementations.put(SortedSet.class,  TreeSet.class);
        interfaceImplementations.put(Queue.class,      LinkedList.class);
        interfaceImplementations.put(Map.class,        HashMap.class);
        interfaceImplementations.put(SortedMap.class,  TreeMap.class);

        primitiveDefaults.put(Boolean.TYPE,    false);
        primitiveDefaults.put(Character.TYPE, '\0');
        primitiveDefaults.put(Byte.TYPE,       new Byte("0"));
        primitiveDefaults.put(Short.TYPE,      new Short("0"));
        primitiveDefaults.put(Integer.TYPE,    new Integer(0));
        primitiveDefaults.put(Long.TYPE,       new Long(0l));
        primitiveDefaults.put(Float.TYPE,      new Float(0f));
        primitiveDefaults.put(Double.TYPE,     new Double(0.0));
    }

    /**
     * The set of method that annotation classes inherit, and should be avoided when
     * toString()ing an annotation class.
     */
    private static final Set<String> INHERITED_ANNOTATION_METHODS =
            new HashSet(Arrays.asList("toString", "equals", "hashCode", "annotationType"));

    /**
     * Looks up the default implementing type for the supplied interface. This is done
     * based on a static map of known common interface types and implementing classes.
     *
     * @param iface an interface for which an implementing class is needed
     * @return a Class object representing the implementing type, or null if one is
     *         not found
     */
    public static Class<?> getImplementingClass(Class<?> iface) {
        return interfaceImplementations.get(iface);
    }

    /**
     * Attempts to determine an implementing class for the interface provided and instantiate
     * it using a default constructor.
     *
     * @param interfaceType an interface (or abstract class) to make an instance of
     * @return an instance of the interface type supplied
     * @throws InstantiationException if no implementation type has been configured
     * @throws IllegalAccessException if thrown by the JVM during class instantiation
     */
    @SuppressWarnings("unchecked")
  public static <T> T getInterfaceInstance(Class<T> interfaceType)
            throws InstantiationException, IllegalAccessException {
        Class impl = getImplementingClass(interfaceType);
        if (impl == null) {
            throw new InstantiationException(
                    "Stripes needed to instantiate a property who's declared type as an " +
                    "interface (which obviously cannot be instantiated. The interface is not " +
                    "one that Stripes is aware of, so no implementing class was known. The " +
                    "interface type was: '" + interfaceType.getName() + "'. To fix this " +
                    "you'll need to do one of three things. 1) Change the getter/setter methods " +
                    "to use a concrete type so that Stripes can instantiate it. 2) in the bean's " +
                    "setContext() method pre-instantiate the property so Stripes doesn't have to. " +
                    "3) Bug the Stripes author ;)  If the interface is a JDK type it can easily be " +
                    "fixed. If not, if enough people ask, a generic way to handle the problem " +
                    "might get implemented.");
        }
        else {
            return (T) impl.newInstance();
        }
    }

    /**
     * Utility method used to load a class.  Any time that Stripes needs to load of find a
     * class by name it uses this method.  As a result any time the classloading strategy
     * needs to change it can be done in one place!  Currently uses
     * {@code Thread.currentThread().getContextClassLoader().loadClass(String)}.
     *
     * @param name the fully qualified (binary) name of the class to find or load
     * @return the Class object representing the class
     * @throws ClassNotFoundException if the class cannot be loaded
     */
    @SuppressWarnings("unchecked") // this allows us to assign without casting
  public static Class findClass(String name) throws ClassNotFoundException {
        return Thread.currentThread().getContextClassLoader().loadClass(name);
    }

    /**
     * <p>A better (more concise) toString method for annotation types that yields a String
     * that should look more like the actual usage of the annotation in a class. The String produced
     * is similar to that produced by calling toString() on the annotation directly, with the
     * following differences:</p>
     *
     * <ul>
     *   <li>Uses the classes simple name instead of it's fully qualified name.</li>
     *   <li>Only outputs attributes that are set to non-default values.</li>
     *
     * <p>If, for some unforseen reason, an exception is thrown within this method it will be
     * caught and the return value will be {@code ann.toString()}.
     *
     * @param ann the annotation to convert to a human readable String
     * @return a human readable String form of the annotation and it's attributes
     */
    public static String toString(Annotation ann) {
        try {
            Class<? extends Annotation> type = ann.annotationType();
            StringBuilder builder = new StringBuilder(128);
            builder.append("@");
            builder.append(type.getSimpleName());

            boolean appendedAnyParameters = false;
            Method[] methods = type.getMethods();
            for (Method method : methods) {
                if (!INHERITED_ANNOTATION_METHODS.contains(method.getName())) {
                    Object defaultValue = method.getDefaultValue();
                    Object actualValue  = method.invoke(ann);

                    // If we have arrays, they have to be treated a little differently
                    Object[] defaultArray = null, actualArray = null;
                    if ( Object[].class.isAssignableFrom(method.getReturnType()) ) {
                        defaultArray = (Object[]) defaultValue;
                        actualArray  = (Object[]) actualValue;
                    }

                    // Only print an attribute if it isn't set to the default value
                    if ( (defaultArray != null && !Arrays.equals(defaultArray, actualArray)) ||
                            (defaultArray == null && !actualValue.equals(defaultValue)) ) {

                        if (appendedAnyParameters) {
                            builder.append(", ");
                        }
                        else {
                            builder.append("(");
                        }

                        builder.append(method.getName());
                        builder.append("=");

                        if (actualArray != null) {
                            builder.append( Arrays.toString(actualArray) );
                        }
                        else {
                            builder.append(actualValue);
                        }

                        appendedAnyParameters = true;
                    }
                }
            }

            if (appendedAnyParameters) {
                builder.append(")");
            }

            return builder.toString();
        }
        catch (Exception e) {
            return ann.toString();
        }
    }

    /**
     * Fetches all methods of all access types from the supplied class and super
     * classes. Methods that have been overridden in the inheritance hierarchy are
     * only returned once, using the instance lowest down the hierarchy.
     *
     * @param clazz the class to inspect
     * @return a collection of methods
     */
    public static Collection<Method> getMethods(Class<?> clazz) {
        Collection<Method> found = new ArrayList<Method>();
        while (clazz != null) {
            for (Method m1 : clazz.getDeclaredMethods()) {
                boolean overridden = false;

                for (Method m2 : found) {
                    if ( m2.getName().equals(m1.getName()) &&
                            Arrays.deepEquals(m1.getParameterTypes(), m2.getParameterTypes())) {
                        overridden = true;
                        break;
                    }
                }

                if (!overridden) found.add(m1);
            }

            clazz = clazz.getSuperclass();
        }

        return found;
    }

    /**
     * Fetches all fields of all access types from the supplied class and super
     * classes. Fieldss that have been overridden in the inheritance hierarchy are
     * only returned once, using the instance lowest down the hierarchy.
     *
     * @param clazz the class to inspect
     * @return a collection of fields
     */
    public static Collection<Field> getFields(Class<?> clazz) {
        Map<String,Field> fields = new HashMap<String, Field>();
        while (clazz != null) {
            for (Field field : clazz.getDeclaredFields()) {
                if ( !fields.containsKey(field.getName()) ) {
                    fields.put(field.getName(), field);
                }
            }

            clazz = clazz.getSuperclass();
        }

        return fields.values();
    }

    /**
     * Fetches the property descriptor for the named property of the supplied class. To
     * speed things up a cache is maintained of propertyName to PropertyDescriptor for
     * each class used with this method.  If there is no property with the specified name,
     * returns null.
     *
     * @param clazz the class who's properties to examine
     * @param property the String name of the property to look for
     * @return the PropertyDescriptor or null if none is found with a matching name
     */
    public static PropertyDescriptor getPropertyDescriptor(Class<?> clazz, String property) {
        Map<String,PropertyDescriptor> pds = propertyDescriptors.get(clazz);
        if (pds == null) {
            try {
                BeanInfo info = Introspector.getBeanInfo(clazz);
                PropertyDescriptor[] descriptors = info.getPropertyDescriptors();
                pds = new HashMap<String, PropertyDescriptor>();

                for (PropertyDescriptor descriptor : descriptors) {
                    pds.put(descriptor.getName(), descriptor);
                }

                propertyDescriptors.put(clazz, pds);
            }
            catch (IntrospectionException ie) {
                throw new RuntimeException("Could not examine class '" + clazz.getName() +
                        "' using Introspector.getBeanInfo() to determine property information.", ie);
            }
        }

        return pds.get(property);
    }

    /**
     * <p>Attempts to find an accessible version of the method passed in, where accessible
     * is defined as the method itself being public and the declaring class being public.
     * Mostly useful as a workaround to the situation when
     * {@link PropertyDescriptor#getReadMethod()} and/or
     * {@link java.beans.PropertyDescriptor#getWriteMethod()} returns methods that are not
     * accessible (usually due to public implementations of interface methods in private
     * classes).</p>
     *
     * <p>Checks the method passed in and if it already meets these criteria it is returned
     * immediately. In general this leads to very little performance overhead</p>
     *
     * <p>If the method does not meet the criteria then the class' interfaces are scanned
     * for a matching method. If one is not found, then the class' superclass hierarchy
     * is searched. Finally, if no matching method can be found the original method is
     * returned.</p>
     *
     * @param m a method that may or may not be accessible
     * @return either an accessible version of the same method, or the method passed in if
     *         an accessible version cannot be found
     */
    public static Method findAccessibleMethod(final Method m) {
        // If the passed in method is accessible, then just give it back.
        if (isPublic(m.getModifiers()) && isPublic(m.getDeclaringClass().getModifiers())) return m;
        if (m.isAccessible()) return m;

        final Class<?> clazz    = m.getDeclaringClass();
        final String name    = m.getName();
        final Class<?>[] ptypes = m.getParameterTypes();

        // Else, loop through the interfaces for the declaring class, looking for a
        // public version of the method that we can call
        for (Class<?> iface : clazz.getInterfaces()) {
            try {
                Method m2 = iface.getMethod(name, ptypes);
                if (m2.isAccessible()) return m2;
                if (isPublic(iface.getModifiers()) && isPublic(m2.getModifiers())) return m2;
            }
            catch (NoSuchMethodException nsme) { /* Not Unexpected. */ }
        }

        // Else loop through the superclasses looking for a public method
        Class<?> c = clazz.getSuperclass();
        while (c != null) {
            try {
                Method m2 = c.getMethod(name, ptypes);
                if (m2.isAccessible()) return m2;
                if (isPublic(c.getModifiers()) && isPublic(m2.getModifiers())) return m2;
            }
            catch (NoSuchMethodException nsme) { /* Not Unexpected. */ }

            c = c.getSuperclass();
        }

        // If we haven't found anything at this point, just give up!
        return m;
    }



    /**
     * Looks for an instance (i.e. non-static) public field with the matching name and
     * returns it if one exists.  If no such field exists, returns null.
     *
     * @param clazz the clazz who's fields to examine
     * @param property the name of the property/field to look for
     * @return the Field object or null if no matching field exists
     */
    public static Field getField(Class<?> clazz, String property) {
        try {
            Field field = clazz.getField(property);
            return !Modifier.isStatic(field.getModifiers()) ? field : null;
        }
        catch (NoSuchFieldException nsfe) {
            return null;
        }
    }

    /**
     * Returns an appropriate default value for the class supplied. Mirrors the defaults used
     * when the JVM initializes instance variables.
     *
     * @param clazz the class for which to find the default value
     * @return null for non-primitive types and an appropriate wrapper instance for primitives
     */
    public static Object getDefaultValue(Class<?> clazz) {
        if (clazz.isPrimitive()) {
            return primitiveDefaults.get(clazz);
        }
        else {
            return null;
        }
    }
    
    /**
     * Returns a set of all interfaces implemented by class supplied. This includes all
     * interfaces directly implemented by this class as well as those implemented by
     * superclasses or interface superclasses.
     * 
     * @param clazz
     * @return all interfaces implemented by this class
     */
    public static Set<Class<?>> getImplementedInterfaces(Class<?> clazz)
    {
        Set<Class<?>> interfaces = new HashSet<Class<?>>();
        
        if (clazz.isInterface())
            interfaces.add(clazz);

        while (clazz != null) {
            for (Class<?> iface : clazz.getInterfaces())
                interfaces.addAll(getImplementedInterfaces(iface));
            clazz = clazz.getSuperclass();
        } 

        return interfaces;
    }

    /**
     * Returns an array of Type objects representing the actual type arguments
     * to targetType used by clazz.
     * 
     * @param clazz the implementing class (or subclass)
     * @param targetType the implemented generic class or interface
     * @return an array of Type objects or null
     */
    public static Type[] getActualTypeArguments(Class<?> clazz, Class<?> targetType) {
        Set<Class<?>> classes = new HashSet<Class<?>>();
        classes.add(clazz);

        if (targetType.isInterface())
            classes.addAll(getImplementedInterfaces(clazz));

        Class<?> superClass = clazz.getSuperclass();
        while (superClass != null) {
            classes.add(superClass);
            superClass = superClass.getSuperclass();
        }

        for (Class<?> search : classes) {
            for (Type type : (targetType.isInterface() ? search.getGenericInterfaces()
                    : new Type[] { search.getGenericSuperclass() })) {
                if (type instanceof ParameterizedType) {
                    ParameterizedType parameterizedType = (ParameterizedType) type;
                    if (targetType.equals(parameterizedType.getRawType()))
                        return parameterizedType.getActualTypeArguments();
                }
            }
        }

        return null;
    }
}

   
    
    
    
    
    
    
  








Related examples in the same category

1.Method Reflection
2.Load a method on the fly
3.Demonstrates how to get specific method information
4.Class Reflection: show methodsClass Reflection: show methods
5.Object Reflection: invoke methodsObject Reflection: invoke methods
6.To get the calling method
7.Get the class name in a static method
8.Call a method dynamically (Reflection)
9.Call a class method with 2 arguments
10.Using reflection to show all the methods of a class,
11.Invoke method through Java Reflection APIInvoke method through Java Reflection API
12.Get a given method, and invoke it
13.Show loading a class and finding and calling its Main methodShow loading a class and finding and calling its Main method
14.Demonstrates dynamic usage of methods
15.Demonstration of various method invocation issues
16.An invocation handler that counts the number of calls for all methods in the target class.
17.Method modifiers: isSynthetic(), m.isVarArgs(), m.isBridge()
18.Call private method
19.Get the methods of a class object
20.Invoke a method using Method class
21.The next example calls a class method with 2 arguments:
22.Getting the Methods of a Class Object: By obtaining a list of all declared methods
23.Getting the Methods of a Class Object: By obtaining a list of all public methods, both declared and inherited.
24.Getting the Methods of a Class Object: By obtaining a particular Method object.
25.Get the current method name
26.Get the current method name With JDK1.5
27.Get all declared methods from a class
28.Make methods that have unspecified number of parameters:pass an array of Objects
29.Get all methods including the inherited method. Using the getMethods(), we can only access public methods.
30.Find a Method on the supplied class with the supplied name and no parameters
31.Find a Method on the supplied class with the supplied name and parameter types
32.Checks whether the specified class contains a method matching the specified name.
33.Call a member function to get the value
34.Call a method of an object
35.Call a static method of a class with reflection
36.Returns method with the specified name
37.Find method
38.Invokes a method, masking with a runtime exception all the exceptions.
39.Sorts methods according to their name, number of parameters, and parameter types.
40.This program shows how to invoke methods through reflection
41.Adds all methods (from Class.getMethodCalls) to the list
42.Find method 2
43.Find Declared Methods
44.Get Static Method
45.Search Method
46.Convert method to property name.
47.Get all methods of a class.
48.Method signature
49.Gets a String array of all method calls for the given class
50.Convert the Method to a Java Code String (arguments are replaced by the simple types)