![JAR search and dependency download from the Maven repository](/logo.png)
net.abc.tool.util.base.ClassUtils Maven / Gradle / Ivy
package net.abc.tool.util.base;
import net.abc.tool.util.string.StringUtils;
import java.io.Closeable;
import java.io.Externalizable;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.*;
/**
* @author: zhangwei
* @date: 00:02/2018-11-30
*/
public abstract class ClassUtils {
/** Suffix for array class names: {@code "[]"}. */
public static final String ARRAY_SUFFIX = "[]";
/** Prefix for internal array class names: {@code "["}. */
private static final String INTERNAL_ARRAY_PREFIX = "[";
/** Prefix for internal non-primitive array class names: {@code "[L"}. */
private static final String NON_PRIMITIVE_ARRAY_PREFIX = "[L";
/** The package separator character: {@code '.'}. */
private static final char PACKAGE_SEPARATOR = '.';
/** The path separator character: {@code '/'}. */
private static final char PATH_SEPARATOR = '/';
/** The inner class separator character: {@code '$'}. */
private static final char INNER_CLASS_SEPARATOR = '$';
/** The CGLIB class separator: {@code "$$"}. */
public static final String CGLIB_CLASS_SEPARATOR = "$$";
/** The ".class" file suffix. */
public static final String CLASS_FILE_SUFFIX = ".class";
/**
* Map with primitive wrapper type as key and corresponding primitive
* type as value, for example: Integer.class -> int.class.
*/
private static final Map, Class>> primitiveWrapperTypeMap = new IdentityHashMap<>(8);
/**
* Map with primitive type as key and corresponding wrapper
* type as value, for example: int.class -> Integer.class.
*/
private static final Map, Class>> primitiveTypeToWrapperMap = new IdentityHashMap<>(8);
/**
* Map with primitive type name as key and corresponding primitive
* type as value, for example: "int" -> "int.class".
*/
private static final Map> primitiveTypeNameMap = new HashMap<>(32);
/**
* Map with common Java language class name as key and corresponding Class as value.
* Primarily for efficient deserialization of remote invocations.
*/
private static final Map> commonClassCache = new HashMap<>(64);
/**
* Common Java language interfaces which are supposed to be ignored
* when searching for 'primary' user-level interfaces.
*/
private static final Set> javaLanguageInterfaces;
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);
// Map entry iteration is less expensive to initialize than forEach with lambdas
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());
Collections.addAll(primitiveTypes, 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,
Class.class, Class[].class, Object.class, Object[].class);
registerCommonClasses(Throwable.class, Exception.class, RuntimeException.class,
Error.class, StackTraceElement.class, StackTraceElement[].class);
registerCommonClasses(Enum.class, Iterable.class, Iterator.class, Enumeration.class,
Collection.class, List.class, Set.class, Map.class, Map.Entry.class, Optional.class);
Class>[] javaLanguageInterfaceArray = {Serializable.class, Externalizable.class,
Closeable.class, AutoCloseable.class, Cloneable.class, Comparable.class};
registerCommonClasses(javaLanguageInterfaceArray);
javaLanguageInterfaces = new HashSet<>(Arrays.asList(javaLanguageInterfaceArray));
}
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 Class> forName(String name, ClassLoader classLoader)
throws ClassNotFoundException, LinkageError {
if(name == null){
throw new NullPointerException("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 = getDefaultClassLoader();
}
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;
// Most class names will be quite long, considering that they
// SHOULD sit in a package, so a length check is worthwhile.
if (name != null && name.length() <= 8) {
// Could be a primitive - likely.
result = primitiveTypeNameMap.get(name);
}
return result;
}
public static boolean isVisible(Class> clazz, ClassLoader classLoader) {
if (classLoader == null) {
return true;
}
try {
if (clazz.getClassLoader() == classLoader) {
return true;
}
}
catch (SecurityException ex) {
// Fall through to loadable check below
}
// Visible if same Class can be loaded from given ClassLoader
return isLoadable(clazz, classLoader);
}
private static boolean isLoadable(Class> clazz, ClassLoader classLoader) {
try {
return (clazz == classLoader.loadClass(clazz.getName()));
// Else: different class with same name found
}
catch (ClassNotFoundException ex) {
// No corresponding class found at all
return false;
}
}
private static void registerCommonClasses(Class>... commonClasses) {
for (Class> clazz : commonClasses) {
commonClassCache.put(clazz.getName(), clazz);
}
}
public static String getShortName(String className) {
if(StringUtils.isEmpty(className)){
throw new IllegalArgumentException("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 getShortName(Class> clazz) {
return getShortName(getQualifiedName(clazz));
}
public static String getQualifiedName(Class> clazz) {
if(clazz == null){
throw new NullPointerException("Class must not be null");
}
return clazz.getTypeName();
}
public static boolean hasConstructor(Class> clazz, Class>... paramTypes) {
return (getConstructorIfAvailable(clazz, paramTypes) != null);
}
public static Constructor getConstructorIfAvailable(Class clazz, Class>... paramTypes) {
if(clazz == null){
throw new NullPointerException("Class must not be null");
}
try {
return clazz.getConstructor(paramTypes);
}
catch (NoSuchMethodException ex) {
return null;
}
}
public static boolean hasMethod(Class> clazz, String methodName, Class>... paramTypes) {
return (getMethodIfAvailable(clazz, methodName, paramTypes) != null);
}
public static Method getMethodIfAvailable(Class> clazz, String methodName, Class>... paramTypes) {
if(clazz == null){
throw new NullPointerException("Class must not be null");
}
if(methodName == null){
throw new NullPointerException("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;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy