ClassUtil.java
001 package net.sourceforge.pmd.util;
002 
003 import java.lang.reflect.Method;
004 import java.math.BigDecimal;
005 import java.util.ArrayList;
006 import java.util.HashMap;
007 import java.util.List;
008 import java.util.Map;
009 
010 /**
011  * Various class-related utility methods.
012  *
013  @author Brian Remedios
014  */
015 public final class ClassUtil {
016 
017     public static final Class[] EMPTY_CLASS_ARRAY = new Class[0];
018 
019     private ClassUtil() {
020     };
021 
022     @SuppressWarnings("PMD.AvoidUsingShortType")
023     private static final TypeMap PRIMITIVE_TYPE_NAMES = new TypeMap(new Class[] { int.class, byte.class, long.class,
024             short.class, float.class, double.class, char.class, boolean.class, });
025 
026     private static final TypeMap TYPES_BY_NAME = new TypeMap(new Class[] { Integer.class, Byte.class, Long.class,
027             Short.class, Float.class, Double.class, Character.class, Boolean.class, BigDecimal.class, String.class,
028             Object.class, });
029 
030     private static final Map<Class, String> SHORT_NAMES_BY_TYPE = computeClassShortNames();
031     
032     /**
033      * Returns the type(class) for the name specified or null if not found.
034      *
035      @param name String
036      @return Class
037      */
038     public static Class<?> getPrimitiveTypeFor(String name) {
039         return PRIMITIVE_TYPE_NAMES.typeFor(name);
040     }
041 
042     /**
043      * Return a map of all the short names of classes we maintain mappings for.
044      * The names are keyed by the classes themselves.
045      *
046      @return Map<Class, String>
047      */
048     private static Map<Class, String> computeClassShortNames() {
049         
050         Map<Class, String> map = new HashMap<Class, String>();
051         map.putAll(PRIMITIVE_TYPE_NAMES.asInverseWithShortName());
052         map.putAll(TYPES_BY_NAME.asInverseWithShortName());
053         return map;
054     }
055 
056     public static Map<Class, String> getClassShortNames() {
057         return SHORT_NAMES_BY_TYPE;
058     }
059     
060     /**
061      * Attempt to determine the actual class given the short name.
062      *
063      @param shortName String
064      @return Class
065      */
066     public static Class<?> getTypeFor(String shortName) {
067         Class<?> type = TYPES_BY_NAME.typeFor(shortName);
068         if (type != null) {
069             return type;
070         }
071 
072         type = PRIMITIVE_TYPE_NAMES.typeFor(shortName);
073         if (type != null) {
074             return type;
075         }
076 
077         return CollectionUtil.getCollectionTypeFor(shortName);
078     }
079 
080     /**
081      * Return the name of the type in its short form if its known to us
082      * otherwise return its name fully packaged.
083      
084      @param type
085      @return String
086      */
087     public static String asShortestName(Class<?> type) {
088         
089         String name = SHORT_NAMES_BY_TYPE.get(type);
090         return name == null ? type.getName() : name;
091     }
092     
093     /**
094      * Returns the abbreviated name of the type, without the package name
095      *
096      @param fullTypeName
097      @return String
098      */
099 
100     public static String withoutPackageName(String fullTypeName) {
101         int dotPos = fullTypeName.lastIndexOf('.');
102         return dotPos > ? fullTypeName.substring(dotPos + 1: fullTypeName;
103     }
104 
105     /**
106      * Attempts to return the specified method from the class provided but will
107      * walk up its superclasses until it finds a match. Returns null if it
108      * doesn't.
109      *
110      @param clasz     Class
111      @param methodName String
112      @param paramTypes Class[]
113      @return Method
114      */
115     public static Method methodFor(Class<?> clasz, String methodName, Class<?>[] paramTypes) {
116         Method method = null;
117         Class<?> current = clasz;
118         while (current != Object.class) {
119             try {
120                 method = current.getDeclaredMethod(methodName, paramTypes);
121             catch (NoSuchMethodException ex) {
122                 current = current.getSuperclass();
123             }
124             if (method != null) {
125                 return method;
126             }
127         }
128         return null;
129     }
130     
131     /**
132      * Return the methods as a map keyed by their common declaration types.
133      
134      @param methods
135      @return Map<String, List<Method>>
136      */
137     public static Map<String, List<Method>> asMethodGroupsByTypeName(Method[] methods) {
138         
139         Map<String, List<Method>> methodGroups = new HashMap<String, List<Method>>(methods.length);
140         
141         for (int i=0; i<methods.length; i++) {
142             String clsName = ClassUtil.asShortestName(methods[i].getDeclaringClass());
143             if (!methodGroups.containsKey(clsName)) {
144                 methodGroups.put(clsName, new ArrayList<Method>());
145             }
146             methodGroups.get(clsName).add(methods[i]);
147         }
148         return methodGroups;
149     }
150 }