/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.util;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Various class-related utility methods intended for mapping common java.lang
* types to their short short forms allowing end users to enter these names in
* UIs without the package prefixes.
*
* @author Brian Remedios
*/
public final class ClassUtil {
public static final Class<?>[] EMPTY_CLASS_ARRAY = new Class[0];
@SuppressWarnings("PMD.AvoidUsingShortType")
private static final TypeMap PRIMITIVE_TYPE_NAMES = new TypeMap(new Class[] { int.class, byte.class, long.class,
short.class, float.class, double.class, char.class, boolean.class, });
private static final TypeMap TYPES_BY_NAME = new TypeMap(
new Class[] { Integer.class, Byte.class, Long.class, Short.class, Float.class, Double.class,
Character.class, Boolean.class, BigDecimal.class, String.class, Object.class, Class.class, });
private static final Map<Class<?>, String> SHORT_NAMES_BY_TYPE = computeClassShortNames();
private ClassUtil() {
}
/**
* Returns the type(class) for the name specified or null if not found.
*
* @param name
* String
* @return Class
*/
public static Class<?> getPrimitiveTypeFor(String name) {
return PRIMITIVE_TYPE_NAMES.typeFor(name);
}
/**
* Return a map of all the short names of classes we maintain mappings for.
* The names are keyed by the classes themselves.
*
* @return Map<Class, String>
*/
private static Map<Class<?>, String> computeClassShortNames() {
Map<Class<?>, String> map = new HashMap<>();
map.putAll(PRIMITIVE_TYPE_NAMES.asInverseWithShortName());
map.putAll(TYPES_BY_NAME.asInverseWithShortName());
return map;
}
public static Map<Class<?>, String> getClassShortNames() {
return SHORT_NAMES_BY_TYPE;
}
/**
* Attempt to determine the actual class given the short name.
*
* @param shortName
* String
* @return Class
*/
public static Class<?> getTypeFor(String shortName) {
Class<?> type = TYPES_BY_NAME.typeFor(shortName);
if (type != null) {
return type;
}
type = PRIMITIVE_TYPE_NAMES.typeFor(shortName);
if (type != null) {
return type;
}
return CollectionUtil.getCollectionTypeFor(shortName);
}
/**
* Return the name of the type in its short form if its known to us
* otherwise return its name fully packaged.
*
* @param type
* @return String
*/
public static String asShortestName(Class<?> type) {
String name = SHORT_NAMES_BY_TYPE.get(type);
return name == null ? type.getName() : name;
}
/**
* Returns the abbreviated name of the type, without the package name
*
* @param fullTypeName
* @return String
*/
public static String withoutPackageName(String fullTypeName) {
int dotPos = fullTypeName.lastIndexOf('.');
return dotPos > 0 ? fullTypeName.substring(dotPos + 1) : fullTypeName;
}
/**
* Attempts to return the specified method from the class provided but will
* walk up its superclasses until it finds a match. Returns null if it
* doesn't.
*
* @param clasz
* Class
* @param methodName
* String
* @param paramTypes
* Class[]
* @return Method
*/
public static Method methodFor(Class<?> clasz, String methodName, Class<?>[] paramTypes) {
Method method = null;
Class<?> current = clasz;
while (current != Object.class) {
try {
method = current.getDeclaredMethod(methodName, paramTypes);
} catch (NoSuchMethodException ex) {
current = current.getSuperclass();
}
if (method != null) {
return method;
}
}
return null;
}
/**
* Return the methods as a map keyed by their common declaration types.
*
* @param methods
* @return methods grouped by declaring type name
*/
public static Map<String, List<Method>> asMethodGroupsByTypeName(Method[] methods) {
Map<String, List<Method>> methodGroups = new HashMap<>(methods.length);
for (int i = 0; i < methods.length; i++) {
String clsName = asShortestName(methods[i].getDeclaringClass());
if (!methodGroups.containsKey(clsName)) {
methodGroups.put(clsName, new ArrayList<Method>());
}
methodGroups.get(clsName).add(methods[i]);
}
return methodGroups;
}
}