com.github.datalking.util.ClassUtils Maven / Gradle / Ivy
package com.github.datalking.util;
import java.beans.Introspector;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
/**
* @author yaoo on 4/19/18
*/
public abstract class ClassUtils {
public static final String ARRAY_SUFFIX = "[]";
private static final String INTERNAL_ARRAY_PREFIX = "[";
private static final String NON_PRIMITIVE_ARRAY_PREFIX = "[L";
private static final char PACKAGE_SEPARATOR = '.';
private static final char PATH_SEPARATOR = '/';
private static final char INNER_CLASS_SEPARATOR = '$';
public static final String CGLIB_CLASS_SEPARATOR = "$$";
public static final String CLASS_FILE_SUFFIX = ".class";
private static final Map, Class>> primitiveWrapperTypeMap = new IdentityHashMap<>(8);
private static final Map, Class>> primitiveTypeToWrapperMap = new IdentityHashMap<>(8);
private static final Map> primitiveTypeNameMap = new HashMap<>(32);
private static final Map> commonClassCache = new HashMap<>(32);
static {
primitiveWrapperTypeMap.put(Boolean.class, boolean.class);
primitiveWrapperTypeMap.put(Byte.class, byte.class);
primitiveWrapperTypeMap.put(Character.class, char.class);
primitiveWrapperTypeMap.put(Double.class, double.class);
primitiveWrapperTypeMap.put(Float.class, float.class);
primitiveWrapperTypeMap.put(Integer.class, int.class);
primitiveWrapperTypeMap.put(Long.class, long.class);
primitiveWrapperTypeMap.put(Short.class, short.class);
for (Map.Entry, Class>> entry : primitiveWrapperTypeMap.entrySet()) {
primitiveTypeToWrapperMap.put(entry.getValue(), entry.getKey());
registerCommonClasses(entry.getKey());
}
Set> primitiveTypes = new HashSet>(32);
primitiveTypes.addAll(primitiveWrapperTypeMap.values());
primitiveTypes.addAll(Arrays.asList(new Class>[]{
boolean[].class, byte[].class, char[].class, double[].class,
float[].class, int[].class, long[].class, short[].class}));
primitiveTypes.add(void.class);
for (Class> primitiveType : primitiveTypes) {
primitiveTypeNameMap.put(primitiveType.getName(), primitiveType);
}
registerCommonClasses(Boolean[].class, Byte[].class, Character[].class, Double[].class,
Float[].class, Integer[].class, Long[].class, Short[].class);
registerCommonClasses(Number.class, Number[].class, String.class, String[].class,
Object.class, Object[].class, Class.class, Class[].class);
registerCommonClasses(Throwable.class, Exception.class, RuntimeException.class,
Error.class, StackTraceElement.class, StackTraceElement[].class);
}
private static void registerCommonClasses(Class>... commonClasses) {
for (Class> clazz : commonClasses) {
commonClassCache.put(clazz.getName(), clazz);
}
}
public static String getCamelCaseNameFromClass(Class> clazz) {
String className = clazz.getName();
int lastDotIdx = className.lastIndexOf(".");
if (lastDotIdx != -1) {
className = className.substring(lastDotIdx + 1);
}
return StringUtils.firstLetterLowerCase(className);
}
public static Class>[] getAllInterfacesForClass(Class> clazz) {
return getAllInterfacesForClass(clazz, null);
}
public static Class>[] getAllInterfacesForClass(Class> clazz, ClassLoader classLoader) {
Set> ifcs = getAllInterfacesForClassAsSet(clazz, classLoader);
return ifcs.toArray(new Class>[ifcs.size()]);
}
public static Set> getAllInterfacesForClassAsSet(Class> clazz) {
return getAllInterfacesForClassAsSet(clazz, null);
}
// 返回clazz类及其超类实现的所有接口
public static Set> getAllInterfacesForClassAsSet(Class> clazz, ClassLoader classLoader) {
Assert.notNull(clazz, "Class must not be null");
if (clazz.isInterface() && isVisible(clazz, classLoader)) {
return Collections.singleton(clazz);
}
Set> interfaces = new LinkedHashSet<>();
while (clazz != null) {
Class>[] ifcs = clazz.getInterfaces();
for (Class> ifc : ifcs) {
// 递归查询并加入
interfaces.addAll(getAllInterfacesForClassAsSet(ifc, classLoader));
}
clazz = clazz.getSuperclass();
}
return interfaces;
}
public static boolean isVisible(Class> clazz, ClassLoader classLoader) {
if (classLoader == null) {
return true;
}
try {
Class> actualClass = classLoader.loadClass(clazz.getName());
return (clazz == actualClass);
} catch (ClassNotFoundException ex) {
return false;
}
}
public static boolean isAssignableValue(Class> type, Object value) {
Assert.notNull(type, "Type must not be null");
return (value != null ? isAssignable(type, value.getClass()) : !type.isPrimitive());
}
/**
* 判断c1是否是c2的父类或父接口
*/
public static boolean isAssignable(Class> c1, Class> c2) {
Assert.notNull(c1, "Left-hand side type must not be null");
Assert.notNull(c2, "Right-hand side type must not be null");
if (c1.isAssignableFrom(c2)) {
return true;
}
if (c1.isPrimitive()) {
Class> resolvedPrimitive = primitiveWrapperTypeMap.get(c2);
if (c1 == resolvedPrimitive) {
return true;
}
} else {
Class> resolvedWrapper = primitiveTypeToWrapperMap.get(c2);
if (resolvedWrapper != null && c1.isAssignableFrom(resolvedWrapper)) {
return true;
}
}
return false;
}
public static Method getMostSpecificMethod(Method method, Class> targetClass) {
if (method != null && isOverridable(method, targetClass) &&
targetClass != null && targetClass != method.getDeclaringClass()) {
try {
if (Modifier.isPublic(method.getModifiers())) {
try {
return targetClass.getMethod(method.getName(), method.getParameterTypes());
} catch (NoSuchMethodException ex) {
return method;
}
} else {
Method specificMethod = ReflectionUtils.findMethod(targetClass, method.getName(), method.getParameterTypes());
return (specificMethod != null ? specificMethod : method);
}
} catch (SecurityException ex) {
// Security settings are disallowing reflective access; fall back to 'method' below.
}
}
return method;
}
private static boolean isOverridable(Method method, Class> targetClass) {
if (Modifier.isPrivate(method.getModifiers())) {
return false;
}
if (Modifier.isPublic(method.getModifiers()) || Modifier.isProtected(method.getModifiers())) {
return true;
}
return getPackageName(method.getDeclaringClass()).equals(getPackageName(targetClass));
}
public static String getPackageName(Class> clazz) {
Assert.notNull(clazz, "Class must not be null");
return getPackageName(clazz.getName());
}
public static String getPackageName(String fqClassName) {
Assert.notNull(fqClassName, "Class name must not be null");
int lastDotIndex = fqClassName.lastIndexOf(PACKAGE_SEPARATOR);
return (lastDotIndex != -1 ? fqClassName.substring(0, lastDotIndex) : "");
}
public static boolean isPresent(String className, ClassLoader classLoader) {
try {
forName(className, classLoader);
return true;
} catch (Throwable ex) {
// Class or one of its dependencies is not present...
return false;
}
}
public static Class> forName(String name, ClassLoader classLoader) throws ClassNotFoundException, LinkageError {
Assert.notNull(name, "Name must not be null");
Class> clazz = resolvePrimitiveClassName(name);
if (clazz == null) {
clazz = commonClassCache.get(name);
}
if (clazz != null) {
return clazz;
}
// "java.lang.String[]" style arrays
if (name.endsWith(ARRAY_SUFFIX)) {
String elementClassName = name.substring(0, name.length() - ARRAY_SUFFIX.length());
Class> elementClass = forName(elementClassName, classLoader);
return Array.newInstance(elementClass, 0).getClass();
}
// "[Ljava.lang.String;" style arrays
if (name.startsWith(NON_PRIMITIVE_ARRAY_PREFIX) && name.endsWith(";")) {
String elementName = name.substring(NON_PRIMITIVE_ARRAY_PREFIX.length(), name.length() - 1);
Class> elementClass = forName(elementName, classLoader);
return Array.newInstance(elementClass, 0).getClass();
}
// "[[I" or "[[Ljava.lang.String;" style arrays
if (name.startsWith(INTERNAL_ARRAY_PREFIX)) {
String elementName = name.substring(INTERNAL_ARRAY_PREFIX.length());
Class> elementClass = forName(elementName, classLoader);
return Array.newInstance(elementClass, 0).getClass();
}
ClassLoader clToUse = classLoader;
if (clToUse == null) {
clToUse = ClassUtils.class.getClassLoader();
}
try {
return (clToUse != null ? clToUse.loadClass(name) : Class.forName(name));
} catch (ClassNotFoundException ex) {
int lastDotIndex = name.lastIndexOf(PACKAGE_SEPARATOR);
if (lastDotIndex != -1) {
String innerClassName =
name.substring(0, lastDotIndex) + INNER_CLASS_SEPARATOR + name.substring(lastDotIndex + 1);
try {
return (clToUse != null ? clToUse.loadClass(innerClassName) : Class.forName(innerClassName));
} catch (ClassNotFoundException ex2) {
// Swallow - let original exception get through
}
}
throw ex;
}
}
public static Class> resolvePrimitiveClassName(String name) {
Class> result = null;
if (name != null && name.length() <= 8) {
result = primitiveTypeNameMap.get(name);
}
return result;
}
public static Class> getUserClass(Object instance) {
Assert.notNull(instance, "Instance must not be null");
return getUserClass(instance.getClass());
}
public static Class> getUserClass(Class> clazz) {
if (clazz != null && clazz.getName().contains(CGLIB_CLASS_SEPARATOR)) {
Class> superclass = clazz.getSuperclass();
if (superclass != null && !Object.class.equals(superclass)) {
return superclass;
}
}
return clazz;
}
public static ClassLoader getDefaultClassLoader() {
ClassLoader cl = null;
try {
cl = Thread.currentThread().getContextClassLoader();
} catch (Throwable ex) {
// Cannot access thread context ClassLoader - falling back...
}
if (cl == null) {
// No thread context class loader -> use class loader of this class.
cl = ClassUtils.class.getClassLoader();
if (cl == null) {
// getClassLoader() returning null indicates the bootstrap ClassLoader
try {
cl = ClassLoader.getSystemClassLoader();
} catch (Throwable ex) {
// Cannot access system ClassLoader - oh well, maybe the caller can live with null...
}
}
}
return cl;
}
public static String classPackageAsResourcePath(Class> clazz) {
if (clazz == null) {
return "";
}
String className = clazz.getName();
int packageEndIndex = className.lastIndexOf(PACKAGE_SEPARATOR);
if (packageEndIndex == -1) {
return "";
}
String packageName = className.substring(0, packageEndIndex);
return packageName.replace(PACKAGE_SEPARATOR, PATH_SEPARATOR);
}
public static String getClassFileName(Class> clazz) {
Assert.notNull(clazz, "Class must not be null");
String className = clazz.getName();
int lastDotIndex = className.lastIndexOf(PACKAGE_SEPARATOR);
return className.substring(lastDotIndex + 1) + CLASS_FILE_SUFFIX;
}
public static Class> resolveClassName(String className, ClassLoader classLoader) throws IllegalArgumentException {
try {
return forName(className, classLoader);
} catch (ClassNotFoundException ex) {
throw new IllegalArgumentException("Cannot find class [" + className + "]", ex);
} catch (LinkageError ex) {
throw new IllegalArgumentException(
"Error loading class [" + className + "]: problem with class file or dependent class.", ex);
}
}
public static boolean isPrimitiveOrWrapper(Class> clazz) {
Assert.notNull(clazz, "Class must not be null");
return (clazz.isPrimitive() || isPrimitiveWrapper(clazz));
}
public static boolean isPrimitiveWrapper(Class> clazz) {
Assert.notNull(clazz, "Class must not be null");
return primitiveWrapperTypeMap.containsKey(clazz);
}
public static boolean isPrimitiveArray(Class> clazz) {
Assert.notNull(clazz, "Class must not be null");
return (clazz.isArray() && clazz.getComponentType().isPrimitive());
}
public static Method getMethod(Class> clazz, String methodName, Class>... paramTypes) {
Assert.notNull(clazz, "Class must not be null");
Assert.notNull(methodName, "Method name must not be null");
if (paramTypes != null) {
try {
return clazz.getMethod(methodName, paramTypes);
} catch (NoSuchMethodException ex) {
throw new IllegalStateException("Expected method not found: " + ex);
}
} else {
Set candidates = new HashSet(1);
Method[] methods = clazz.getMethods();
for (Method method : methods) {
if (methodName.equals(method.getName())) {
candidates.add(method);
}
}
if (candidates.size() == 1) {
return candidates.iterator().next();
} else if (candidates.isEmpty()) {
throw new IllegalStateException("Expected method not found: " + clazz + "." + methodName);
} else {
throw new IllegalStateException("No unique method found: " + clazz + "." + methodName);
}
}
}
public static Method getMethodIfAvailable(Class> clazz, String methodName, Class>... paramTypes) {
Assert.notNull(clazz, "Class must not be null");
Assert.notNull(methodName, "Method name must not be null");
if (paramTypes != null) {
try {
return clazz.getMethod(methodName, paramTypes);
} catch (NoSuchMethodException ex) {
return null;
}
} else {
Set candidates = new HashSet(1);
Method[] methods = clazz.getMethods();
for (Method method : methods) {
if (methodName.equals(method.getName())) {
candidates.add(method);
}
}
if (candidates.size() == 1) {
return candidates.iterator().next();
}
return null;
}
}
public static String getShortNameAsProperty(Class> clazz) {
String shortName = getShortName(clazz);
int dotIndex = shortName.lastIndexOf(PACKAGE_SEPARATOR);
shortName = (dotIndex != -1 ? shortName.substring(dotIndex + 1) : shortName);
return Introspector.decapitalize(shortName);
}
public static String getShortName(Class> clazz) {
return getShortName(getQualifiedName(clazz));
}
public static String getShortName(String className) {
Assert.hasLength(className, "Class name must not be empty");
int lastDotIndex = className.lastIndexOf(PACKAGE_SEPARATOR);
int nameEndIndex = className.indexOf(CGLIB_CLASS_SEPARATOR);
if (nameEndIndex == -1) {
nameEndIndex = className.length();
}
String shortName = className.substring(lastDotIndex + 1, nameEndIndex);
shortName = shortName.replace(INNER_CLASS_SEPARATOR, PACKAGE_SEPARATOR);
return shortName;
}
public static String getQualifiedName(Class> clazz) {
Assert.notNull(clazz, "Class must not be null");
if (clazz.isArray()) {
return getQualifiedNameForArray(clazz);
} else {
return clazz.getName();
}
}
private static String getQualifiedNameForArray(Class> clazz) {
StringBuilder result = new StringBuilder();
while (clazz.isArray()) {
clazz = clazz.getComponentType();
result.append(ARRAY_SUFFIX);
}
result.insert(0, clazz.getName());
return result.toString();
}
public static Class> resolvePrimitiveIfNecessary(Class> clazz) {
Assert.notNull(clazz, "Class must not be null");
return (clazz.isPrimitive() && clazz != void.class ? primitiveTypeToWrapperMap.get(clazz) : clazz);
}
public static String getDescriptiveType(Object value) {
if (value == null) {
return null;
}
Class> clazz = value.getClass();
if (Proxy.isProxyClass(clazz)) {
StringBuilder result = new StringBuilder(clazz.getName());
result.append(" implementing ");
Class>[] ifcs = clazz.getInterfaces();
for (int i = 0; i < ifcs.length; i++) {
result.append(ifcs[i].getName());
if (i < ifcs.length - 1) {
result.append(',');
}
}
return result.toString();
} else if (clazz.isArray()) {
return getQualifiedNameForArray(clazz);
} else {
return clazz.getName();
}
}
public static boolean hasConstructor(Class> clazz, Class>... paramTypes) {
return (getConstructorIfAvailable(clazz, paramTypes) != null);
}
public static Constructor getConstructorIfAvailable(Class clazz, Class>... paramTypes) {
Assert.notNull(clazz, "Class must not be null");
try {
return clazz.getConstructor(paramTypes);
} catch (NoSuchMethodException ex) {
return null;
}
}
public static Method getStaticMethod(Class> clazz, String methodName, Class>... args) {
Assert.notNull(clazz, "Class must not be null");
Assert.notNull(methodName, "Method name must not be null");
try {
Method method = clazz.getMethod(methodName, args);
return Modifier.isStatic(method.getModifiers()) ? method : null;
} catch (NoSuchMethodException ex) {
return null;
}
}
public static boolean matchesTypeName(Class> clazz, String typeName) {
return (typeName != null &&
(typeName.equals(clazz.getName()) || typeName.equals(clazz.getSimpleName()) ||
(clazz.isArray() && typeName.equals(getQualifiedNameForArray(clazz)))));
}
public static boolean hasMethod(Class> clazz, String methodName, Class>... paramTypes) {
return (getMethodIfAvailable(clazz, methodName, paramTypes) != null);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy