View Javadoc
1   /**
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4   package net.sourceforge.pmd.util;
5   
6   import java.lang.reflect.Method;
7   import java.math.BigDecimal;
8   import java.util.ArrayList;
9   import java.util.HashMap;
10  import java.util.List;
11  import java.util.Map;
12  
13  /**
14   * Various class-related utility methods intended for mapping common java.lang types to their short 
15   * short forms allowing end users to enter these names in UIs without the package prefixes.
16   *
17   * @author Brian Remedios
18   */
19  public final class ClassUtil {
20  
21      public static final Class<?>[] EMPTY_CLASS_ARRAY = new Class[0];
22  
23      private ClassUtil() {
24      }
25  
26      @SuppressWarnings("PMD.AvoidUsingShortType")
27      private static final TypeMap PRIMITIVE_TYPE_NAMES = new TypeMap(new Class[] { int.class, byte.class, long.class,
28              short.class, float.class, double.class, char.class, boolean.class, });
29  
30      private static final TypeMap TYPES_BY_NAME = new TypeMap(new Class[] { Integer.class, Byte.class, Long.class,
31              Short.class, Float.class, Double.class, Character.class, Boolean.class, BigDecimal.class, String.class,
32              Object.class, Class.class});
33  
34      private static final Map<Class<?>, String> SHORT_NAMES_BY_TYPE = computeClassShortNames();
35      
36      /**
37       * Returns the type(class) for the name specified or null if not found.
38       *
39       * @param name String
40       * @return Class
41       */
42      public static Class<?> getPrimitiveTypeFor(String name) {
43          return PRIMITIVE_TYPE_NAMES.typeFor(name);
44      }
45  
46      /**
47       * Return a map of all the short names of classes we maintain mappings for.
48       * The names are keyed by the classes themselves.
49       *
50       * @return Map<Class, String>
51       */
52      private static Map<Class<?>, String> computeClassShortNames() {
53          
54          Map<Class<?>, String> map = new HashMap<>();
55          map.putAll(PRIMITIVE_TYPE_NAMES.asInverseWithShortName());
56          map.putAll(TYPES_BY_NAME.asInverseWithShortName());
57          return map;
58      }
59  
60      public static Map<Class<?>, String> getClassShortNames() {
61          return SHORT_NAMES_BY_TYPE;
62      }
63      
64      /**
65       * Attempt to determine the actual class given the short name.
66       *
67       * @param shortName String
68       * @return Class
69       */
70      public static Class<?> getTypeFor(String shortName) {
71          Class<?> type = TYPES_BY_NAME.typeFor(shortName);
72          if (type != null) {
73              return type;
74          }
75  
76          type = PRIMITIVE_TYPE_NAMES.typeFor(shortName);
77          if (type != null) {
78              return type;
79          }
80  
81          return CollectionUtil.getCollectionTypeFor(shortName);
82      }
83  
84      /**
85       * Return the name of the type in its short form if its known to us
86       * otherwise return its name fully packaged.
87       * 
88       * @param type
89       * @return String
90       */
91      public static String asShortestName(Class<?> type) {
92          
93          String name = SHORT_NAMES_BY_TYPE.get(type);
94          return name == null ? type.getName() : name;
95      }
96      
97      /**
98       * Returns the abbreviated name of the type, without the package name
99       *
100      * @param fullTypeName
101      * @return String
102      */
103 
104     public static String withoutPackageName(String fullTypeName) {
105         int dotPos = fullTypeName.lastIndexOf('.');
106         return dotPos > 0 ? fullTypeName.substring(dotPos + 1) : fullTypeName;
107     }
108 
109     /**
110      * Attempts to return the specified method from the class provided but will
111      * walk up its superclasses until it finds a match. Returns null if it
112      * doesn't.
113      *
114      * @param clasz		 Class
115      * @param methodName String
116      * @param paramTypes Class[]
117      * @return Method
118      */
119     public static Method methodFor(Class<?> clasz, String methodName, Class<?>[] paramTypes) {
120         Method method = null;
121         Class<?> current = clasz;
122         while (current != Object.class) {
123             try {
124                 method = current.getDeclaredMethod(methodName, paramTypes);
125             } catch (NoSuchMethodException ex) {
126                 current = current.getSuperclass();
127             }
128             if (method != null) {
129                 return method;
130             }
131         }
132         return null;
133     }
134     
135     /**
136      * Return the methods as a map keyed by their common declaration types.
137      * 
138      * @param methods
139      * @return Map<String, List<Method>>
140      */
141     public static Map<String, List<Method>> asMethodGroupsByTypeName(Method[] methods) {
142         
143         Map<String, List<Method>> methodGroups = new HashMap<>(methods.length);
144         
145         for (int i=0; i<methods.length; i++) {
146             String clsName = asShortestName(methods[i].getDeclaringClass());
147             if (!methodGroups.containsKey(clsName)) {
148                 methodGroups.put(clsName, new ArrayList<Method>());
149             }
150             methodGroups.get(clsName).add(methods[i]);
151         }
152         return methodGroups;
153     }
154 }