A better concise toString method for annotation types : Annotation « Reflection « Java

Java
1. 2D Graphics GUI
2. 3D
3. Advanced Graphics
4. Ant
5. Apache Common
6. Chart
7. Class
8. Collections Data Structure
9. Data Type
10. Database SQL JDBC
11. Design Pattern
12. Development Class
13. EJB3
14. Email
15. Event
16. File Input Output
17. Game
18. Generics
19. GWT
20. Hibernate
21. I18N
22. J2EE
23. J2ME
24. JDK 6
25. JNDI LDAP
26. JPA
27. JSP
28. JSTL
29. Language Basics
30. Network Protocol
31. PDF RTF
32. Reflection
33. Regular Expressions
34. Scripting
35. Security
36. Servlets
37. Spring
38. Swing Components
39. Swing JFC
40. SWT JFace Eclipse
41. Threads
42. Tiny Application
43. Velocity
44. Web Services SOA
45. XML
Java Tutorial
Java Source Code / Java Documentation
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java » Reflection » AnnotationScreenshots 
A better concise toString method for annotation types
 
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 (Timpl.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 namethrows 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.appendArrays.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 (!overriddenfound.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 = (ParameterizedTypetype;
                    if (targetType.equals(parameterizedType.getRawType()))
                        return parameterizedType.getActualTypeArguments();
                }
            }
        }

        return null;
    }
}

   
  
Related examples in the same category
1. Uses reflection to display the annotation associated with a method.
2. Get annotation by annotation class
3. Show all annotations for a class and a method.
4. default values in an annotation.
5. Does a method have an annotation
6. Get Annotation Parameter
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.