All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.nervousync.utils.ClassUtils Maven / Gradle / Ivy

There is a newer version: 1.2.1
Show newest version
/*
 * Licensed to the Nervousync Studio (NSYC) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.nervousync.utils;

import jakarta.xml.bind.annotation.XmlRootElement;
import jakarta.xml.bind.annotation.XmlType;
import org.nervousync.beans.core.BeanObject;
import org.nervousync.commons.Globals;
import org.nervousync.enumerations.xml.DataType;

import java.lang.reflect.*;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.ParseException;
import java.util.*;
import java.util.stream.Stream;

/**
 * 

Class Operate Utilities

*

类操作工具集

* * @author Steven Wee [email protected] * @version $Revision: 1.2.0 $ $Date: Jan 13, 2010 15:53:41 $ */ public final class ClassUtils { /** * Suffix for array class names: "[]" * 数组类名称后缀:“[]” */ private static final String ARRAY_SUFFIX = "[]"; /** * Prefix for internal array class names: "[L" * 内部数组类名的前缀:“[L” */ private static final String INTERNAL_ARRAY_PREFIX = "[L"; /** * The inner class separator character '$' * 内部类分隔符'$' */ private static final char INNER_CLASS_SEPARATOR = '$'; /** * The CGLIB class separator character "$$" * CGLIB 类分隔符“$$” */ private static final String CGLIB_CLASS_SEPARATOR = "$$"; /** * The Bytebuddy class separator character "$ByteBuddy" * Bytebuddy 类分隔符“$ByteBuddy” */ private static final String BYTEBUDDY_CLASS_SEPARATOR = "$ByteBuddy"; /** * The ".class" file suffix * “.class”文件后缀 */ public static final String CLASS_FILE_SUFFIX = ".class"; /** * Simple data types list * 简单数据类型列表 */ private static final List SIMPLE_DATA_TYPES = Arrays.asList(DataType.NUMBER, DataType.STRING, DataType.BOOLEAN, DataType.DATE); /** * * Map with the primitive wrapper type as a key and corresponding primitive type as value, * for example: Integer.class -> int.class. * * 以原始包装类型作为键并以相应的原始类型作为值进行映射,例如:Integer.class -> int.class。 */ private static final Map PRIMITIVE_WRAPPER_TYPE_MAP = new HashMap<>(8); /** * * Map with primitive type name as a key and corresponding primitive type as value, * for example: "int" -> "int.class". * * 以原始类型名称作为键,以相应的原始类型作为值的映射,例如:“int”->“int.class”。 */ private static final Map PRIMITIVE_TYPE_NAME_MAP = new HashMap<>(16); /** * Default classloader of utilities * 工具集用的默认类加载器 */ private static ClassLoader DEFAULT_CLASSLOADER = null; static { PRIMITIVE_WRAPPER_TYPE_MAP.put(Boolean.class, boolean.class); PRIMITIVE_WRAPPER_TYPE_MAP.put(Byte.class, byte.class); PRIMITIVE_WRAPPER_TYPE_MAP.put(Character.class, char.class); PRIMITIVE_WRAPPER_TYPE_MAP.put(Double.class, double.class); PRIMITIVE_WRAPPER_TYPE_MAP.put(Float.class, float.class); PRIMITIVE_WRAPPER_TYPE_MAP.put(Integer.class, int.class); PRIMITIVE_WRAPPER_TYPE_MAP.put(Long.class, long.class); PRIMITIVE_WRAPPER_TYPE_MAP.put(Short.class, short.class); Set primitiveTypeNames = new HashSet<>(16); primitiveTypeNames.addAll(PRIMITIVE_WRAPPER_TYPE_MAP.values()); primitiveTypeNames.addAll(Arrays.asList( boolean[].class, byte[].class, char[].class, double[].class, float[].class, int[].class, long[].class, short[].class)); primitiveTypeNames.forEach(primitiveClass -> PRIMITIVE_TYPE_NAME_MAP.put(((Class)primitiveClass).getName(), primitiveClass)); } /** *

Private constructor for ClassUtils

*

类操作工具集的私有构造函数

*/ private ClassUtils() { } /** *

Check type class is simple data class, e.g. Number(include int, Integer, long, Long...), String, boolean and Date

*

检查类型类是简单的数据类,例如Number(包括 int、Integer、long、Long...)、String、布尔值和日期时间

* * @param typeClass Will check for type class * 要检查的数据类 * * @return Check result * 检查结果 */ public static boolean simpleDataType(final Class typeClass) { return SIMPLE_DATA_TYPES.contains(retrieveSimpleDataType(typeClass)); } /** *

Retrieve simple data type enumeration value of the given data type class.

*

检索给定数据类型类的简单数据类型枚举值。

* * @param clazz data type class * 数据类型类 * * @return Retrieved simple data type enumeration value * 检索到的简单数据类型枚举值 */ public static DataType retrieveSimpleDataType(final Class clazz) { if (clazz == null) { return DataType.UNKNOWN; } if (clazz.equals(Character[].class) || clazz.equals(char[].class)) { return DataType.CDATA; } else if (clazz.equals(Byte[].class) || clazz.equals(byte[].class)) { return DataType.BINARY; } else if (clazz.equals(Boolean.class) || clazz.equals(boolean.class)) { return DataType.BOOLEAN; } else if (clazz.equals(Date.class)) { return DataType.DATE; } else if (clazz.equals(Integer.class) || clazz.equals(int.class) || clazz.equals(Float.class) || clazz.equals(float.class) || clazz.equals(Double.class) || clazz.equals(double.class) || clazz.equals(Short.class) || clazz.equals(short.class) || clazz.equals(Long.class) || clazz.equals(long.class) || clazz.equals(byte.class) || clazz.equals(BigInteger.class) || clazz.equals(BigDecimal.class) || clazz.equals(Number.class)) { return DataType.NUMBER; } else if (clazz.equals(String.class)) { return DataType.STRING; } else if (BeanObject.class.isAssignableFrom(clazz) && (clazz.isAnnotationPresent(XmlType.class) || clazz.isAnnotationPresent(XmlRootElement.class))) { return DataType.OBJECT; } else if (clazz.isEnum()) { return DataType.ENUM; } else { return DataType.UNKNOWN; } } /** *

Parse simple data value to target class instance.

*

解析简单数据类型值为目标类实例对象。

* * @param Target type class * 目标数据类 * @param dataValue simple data value * 简单数据类型值 * @param typeClass Target type class * 目标数据类 * * @return Target class instance * 目标类实例对象 * * @throws ParseException * If given data value string is null * 如果给定的数据值字符串为null */ public static T parseSimpleData(final String dataValue, final Class typeClass) throws ParseException { Object paramObj = null; if (dataValue == null || typeClass == null || Globals.DEFAULT_VALUE_STRING.equals(dataValue)) { return null; } if (BeanObject.class.isAssignableFrom(typeClass)) { paramObj = StringUtils.stringToObject(dataValue, typeClass); } else { DataType dataType = retrieveSimpleDataType(typeClass); switch (dataType) { case BOOLEAN: paramObj = Boolean.valueOf(dataValue); break; case DATE: paramObj = DateTimeUtils.parseSiteMapDate(dataValue); break; case ENUM: paramObj = ReflectionUtils.parseEnum(typeClass, dataValue); break; case NUMBER: if (typeClass.equals(Integer.class) || typeClass.equals(int.class)) { paramObj = Integer.valueOf(dataValue); } else if (typeClass.equals(Float.class) || typeClass.equals(float.class)) { paramObj = Float.valueOf(dataValue); } else if (typeClass.equals(Double.class) || typeClass.equals(double.class)) { paramObj = Double.valueOf(dataValue); } else if (typeClass.equals(Short.class) || typeClass.equals(short.class)) { paramObj = Short.valueOf(dataValue); } else if (typeClass.equals(Long.class) || typeClass.equals(long.class)) { paramObj = Long.valueOf(dataValue); } else if (typeClass.equals(BigInteger.class)) { paramObj = new BigInteger(dataValue); } break; case CDATA: paramObj = StringUtils.formatForText(dataValue).toCharArray(); break; case BINARY: paramObj = StringUtils.base64Decode( StringUtils.replace(dataValue, " ", Globals.DEFAULT_VALUE_STRING)); break; default: paramObj = StringUtils.formatForText(dataValue); } } return typeClass.cast(paramObj); } /** *

Return the default ClassLoader to use

* * typically the thread context ClassLoader, if available; * the ClassLoader that loaded the ClassUtils class will be used as fallback. * Call this method if you intend to use the thread context ClassLoader * in a scenario where you absolutely need a non-null ClassLoader reference: * for example, for class path resource loading (but not necessarily for * Class.forName, which accepts a null ClassLoader * reference as well). * *

返回要使用的默认类加载器

* * 通常是线程上下文类加载器(如果可用);加载 ClassUtils 类的类加载器将用作后备。 * 如果您打算在绝对需要非空类加载器引用的情况下使用线程上下文类加载器,请调用此方法: * 例如,用于类路径资源加载(但不一定用于 Class.forName,它也接受 null ClassLoader 引用)。 * * @see java.lang.Thread#getContextClassLoader() java.lang.Thread#getContextClassLoader() * * @return the default ClassLoader (never null) * 默认的类加载器(永远不为null */ public static ClassLoader getDefaultClassLoader() { if (DEFAULT_CLASSLOADER != null) { return DEFAULT_CLASSLOADER; } try { return Thread.currentThread().getContextClassLoader(); } catch (Throwable ex) { // Cannot access thread context ClassLoader - falling back to system class loader... return ClassUtils.class.getClassLoader(); } } /** *

Override the thread context ClassLoader

* * Override the thread context ClassLoader with the environment's bean ClassLoader if necessary, * i.e., if the bean ClassLoader is not equivalent to the thread context ClassLoader already. * *

重写线程上下文类加载器

* 如有必要,建议使用环境的类加载器覆写线程上下文类加载器。 * * @param classLoaderToUse the actual ClassLoader to use for the thread context * 用于线程上下文的实际类加载器 * * @return the original thread context ClassLoader, or null if not overridden * 原始线程上下文类加载器,如果未覆盖则为 null */ public static ClassLoader overrideThreadContextClassLoader(final ClassLoader classLoaderToUse) { Thread thread = Thread.currentThread(); ClassLoader contextClassLoader = thread.getContextClassLoader(); if (classLoaderToUse != null && !classLoaderToUse.equals(contextClassLoader)) { thread.setContextClassLoader(classLoaderToUse); DEFAULT_CLASSLOADER = classLoaderToUse; return contextClassLoader; } return null; } /** *

Determine whether the Class identified by the supplied name is present and can be loaded.

* * Will return Boolean.FALSE if either the class or * one of its dependencies is not present or cannot be loaded. * *

确定由提供的名称标识的 Class 是否存在并且可以加载。

* 如果类或其依赖项之一不存在或无法加载,将返回 Boolean.FALSE。 * * @param className the name of the class to check * 要检查的类的名称 * * @return whether the specified class is present * 指定的类是否存在 */ public static boolean isPresent(final String className) { return isPresent(className, getDefaultClassLoader()); } /** *

Determine whether the Class identified by the supplied name is present and can be loaded.

* * Will return Boolean.FALSE if either the class or * one of its dependencies is not present or cannot be loaded. * *

确定由提供的名称标识的 Class 是否存在并且可以加载。

* 如果类或其依赖项之一不存在或无法加载,将返回 Boolean.FALSE。 * * @param className the name of the class to check * 要检查的类的名称 * @param classLoader the ClassLoader to use (maybe null, which indicates the default ClassLoader) * 要使用的类加载器(可能是 null,这表示默认的类加载器) * * @return whether the specified class is present * 指定的类是否存在 */ public static boolean isPresent(final String className, final ClassLoader classLoader) { try { forName(className, classLoader); return Boolean.TRUE; } catch (Throwable ex) { // Class or one of its dependencies is not present... return Boolean.FALSE; } } /** *

Check whether the given exception is compatible with the exceptions declared in a throw clause.

*

检查给定的异常是否与 throw 子句中声明的异常兼容。

* * @param ex the exception to checked * 要检查的异常 * @param declaredExceptions the exceptions declared in the throw clause * throw 子句中声明的异常 * * @return whether the given exception is compatible * 给定的异常是否兼容 */ public static boolean isCompatibleWithThrowClause(final Throwable ex, final Class[] declaredExceptions) { if (ex instanceof RuntimeException || ex instanceof Error) { return Boolean.TRUE; } if (declaredExceptions != null) { return Arrays.stream(declaredExceptions) .anyMatch(declaredException -> ClassUtils.isAssignableValue(declaredException, ex)); } return Boolean.FALSE; } /** *

Parse the original class name of given class instance

*

Unwrap the class name if class was enhancer by cglib/bytebuddy or class name if class not enhanced

*

解析给定类对象的原始类名

*

如果给定的类是经过cglib/bytebuddy增强过,则解析原始类名,如果给定的类没有增强,则返回类名

* * @param clazz Given class instance * 给定的类对象 * * @return Parsed class name string * 解析的类名字符串 */ public static String originalClassName(final Class clazz) { String className = clazz.getName(); if (className.contains(CGLIB_CLASS_SEPARATOR)) { // Process for cglib className = className.substring(0, className.indexOf(CGLIB_CLASS_SEPARATOR)); } else if (className.contains(BYTEBUDDY_CLASS_SEPARATOR)) { // Process for ByteBuddy className = className.substring(0, className.indexOf(BYTEBUDDY_CLASS_SEPARATOR)); } return className; } /** *

Replacement for Class.forName()

* * Replacement for Class.forName() that also returns Class instances * for primitives (like "int") and array class names (like "String[]"). * Always uses the default class loader: that is, preferably the thread context * ClassLoader, or the ClassLoader that loaded the ClassUtils class as fallback. * *

替换 Class.forName()

* * 替换 Class.forName(),它还返回基础类型(如“int”)和数组类名称(如“String[]”)的类实例。 * 始终使用默认的类加载器:最好是线程上下文类加载器,或者加载 ClassUtils 类作为后备的类加载器。 * * @see Class#forName(String, boolean, ClassLoader) Class#forName(String, boolean, ClassLoader) * @see ClassUtils#getDefaultClassLoader() * * @param className the name of the class * 类的名称 * * @return Class instance for the supplied name * 提供的名称的类实例 * * @throws IllegalArgumentException * if the class name was not resolvable (that is, the class could not be found or the class file could not be loaded) * 如果类名不可解析(即找不到类或无法加载类文件) */ public static Class forName(final String className) throws IllegalArgumentException { return forName(className, getDefaultClassLoader()); } /** *

Replacement for Class.forName()

* * Replacement for Class.forName() that also returns Class instances * for primitives (like "int") and array class names (like "String[]"). * *

替换 Class.forName()

* * 替换 Class.forName(),它还返回基础类型(如“int”)和数组类名称(如“String[]”)的类实例。 * * @see Class#forName(String, boolean, ClassLoader) Class#forName(String, boolean, ClassLoader) * * @param className the name of the class * 类的名称 * @param classLoader the ClassLoader to use (maybe null, which indicates the default ClassLoader) * 要使用的类加载器(可能是 null,这表示默认的类加载器) * * @return Class instance for the supplied name * 提供的名称的类实例 * * @throws IllegalArgumentException * if the class name was not resolvable (that is, the class could not be found or the class file could not be loaded) * 如果类名不可解析(即找不到类或无法加载类文件) */ public static Class forName(final String className, final ClassLoader classLoader) throws IllegalArgumentException { if (StringUtils.isEmpty(className)) { throw new IllegalArgumentException("Class name must not be empty"); } if (StringUtils.notBlank(className) && className.length() <= 8 && PRIMITIVE_TYPE_NAME_MAP.containsKey(className)) { return (Class) PRIMITIVE_TYPE_NAME_MAP.get(className); } // "java.lang.String[]" style arrays if (className.endsWith(ARRAY_SUFFIX)) { String elementClassName = className.substring(0, className.length() - ARRAY_SUFFIX.length()); Class elementClass = forName(elementClassName, classLoader); return Array.newInstance(elementClass, 0).getClass(); } int internalArrayMarker = className.indexOf(INTERNAL_ARRAY_PREFIX); if (internalArrayMarker != -1 && className.endsWith(";")) { String elementClassName = null; if (internalArrayMarker == 0) { elementClassName = className.substring(INTERNAL_ARRAY_PREFIX.length(), className.length() - 1); } else if (className.startsWith("[")) { elementClassName = className.substring(1); } Class elementClass = forName(elementClassName, classLoader); return Array.newInstance(elementClass, 0).getClass(); } ClassLoader classLoaderToUse = classLoader; if (classLoaderToUse == null) { classLoaderToUse = getDefaultClassLoader(); } try { return classLoaderToUse.loadClass(className); } catch (ClassNotFoundException ex) { throw new IllegalArgumentException("Cannot find class [" + className + "]", ex); } } /** *

Check whether the given class is cache-safe in the given context

* whether it is loaded by the given ClassLoader or a parent of it. *

检查给定类在给定上下文中是否是缓存安全的

* 它是由给定的类加载器还是其父类加载。 * * @param clazz the class to analyze * 要分析的类 * @param classLoader the ClassLoader to potentially cache metadata in * 可能会缓存元数据的类加载器 * * @return cache safe result * 缓存安全结果 */ public static boolean cacheSafe(final Class clazz, final ClassLoader classLoader) { if (clazz == null) { throw new IllegalArgumentException("Class must not be null"); } ClassLoader target = clazz.getClassLoader(); if (target == null) { return Boolean.FALSE; } ClassLoader cur = classLoader; if (cur == target) { return Boolean.TRUE; } while (cur != null) { cur = cur.getParent(); if (cur == target) { return Boolean.TRUE; } } return Boolean.FALSE; } /** *

Determine the resource name of the class file, relative to the containing package: e.g. "String.class"

*

确定类文件的资源路径:例如“String.class”

* * @param clazz the class instance * 类实例对象 * * @return the resource path of the ".class" file * ".class"文件的资源路径 */ public static String classFileName(final Class clazz) { if (clazz == null) { throw new IllegalArgumentException("Class must not be null"); } String className = clazz.getName(); int lastDotIndex = className.lastIndexOf(Globals.DEFAULT_PACKAGE_SEPARATOR); return className.substring(lastDotIndex + 1) + CLASS_FILE_SUFFIX; } /** *

Determine the package name of the given class.

* e.g. "java.lang" for the java.lang.String class. *

确定给定类的包名称。

* 例如:java.lang.String -> “java.lang” * * @param clazz the class instance * 类实例对象 * * @return the package name, or the empty String if the class is defined in the default package * 包名称,如果类是在默认包中定义的,则为空字符串 */ public static String packageName(final Class clazz) { if (clazz == null) { throw new IllegalArgumentException("Class must not be null"); } String className = clazz.getName(); int lastDotIndex = className.lastIndexOf(Globals.DEFAULT_PACKAGE_SEPARATOR); return (lastDotIndex != -1 ? className.substring(0, lastDotIndex) : Globals.DEFAULT_VALUE_STRING); } /** *

Return the qualified name of the given class.

* usually simply the class name, but component type class name + "[]" for arrays. *

返回给定类的限定名称。

* 通常只是类名,但对于数组来说组件类型类名+“[]”。 * * @param clazz the class instance * 类实例对象 * * @return the qualified name of the class * 类的限定名称 */ public static String qualifiedName(final Class clazz) { if (clazz == null) { throw new IllegalArgumentException("Class must not be null"); } if (clazz.isArray()) { return getQualifiedNameForArray(clazz); } else { return clazz.getName(); } } /** *

Return a descriptive name for the given object's type.

* * usually simply the class name, but component type class name + "[]" for arrays, * and an appended list of implemented interfaces for JDK proxies. * *

返回给定对象类型的描述性名称。

* 通常只是类名,但组件类型类名+数组的“[]”,以及JDK代理的已实现接口的附加列表。 * * @param value the value to introspect * 给定实例对象 * * @return the descriptive name of the class * 实现的接口名称 */ public static String descriptiveType(final Object value) { if (value == null) { return null; } Class clazz = value.getClass(); if (Proxy.isProxyClass(clazz)) { final StringBuilder stringBuilder = new StringBuilder(); Arrays.asList(clazz.getInterfaces()) .forEach(interfaceClass -> stringBuilder.append(",").append(interfaceClass.getName())); return clazz.getName() + " implementing " + stringBuilder.substring(1); } else if (clazz.isArray()) { return getQualifiedNameForArray(clazz); } else { return clazz.getName(); } } /** *

Retrieve the primitive class of the given class.

*

检索给定类的原始类。

* * @param clazz the class instance * 类实例对象 * * @return the primitive class or null if not found * 原始类,如果未找到则返回null */ public static Class primitiveWrapper(final Class clazz) { if (clazz.isPrimitive()) { for (Map.Entry entry : PRIMITIVE_WRAPPER_TYPE_MAP.entrySet()) { if (entry.getValue().equals(clazz)) { return (Class)entry.getKey(); } } } return null; } /** *

Check the given check class and match class is mapping for primitive class -> wrapper class

*

检查给定的检查类和匹配类是否满足映射为原始类 -> 包装类

* * @param checkClass the check class * 检查类 * @param matchClass the match class * 匹配类 * * @return Match result * 匹配结果 */ public static boolean matchPrimitiveWrapper(final Class checkClass, final Class matchClass) { if (isPrimitiveWrapper(checkClass)) { return PRIMITIVE_WRAPPER_TYPE_MAP.get(checkClass).equals(matchClass); } else if (isPrimitiveWrapper(matchClass)) { return PRIMITIVE_WRAPPER_TYPE_MAP.get(matchClass).equals(checkClass); } else { return Boolean.FALSE; } } /** *

Check if the given class represents a primitive wrapper.

* i.e. Boolean, Byte, Character, Short, Integer, Long, Float, or Double. *

检查给定的类是否表示基础类型包装类。

* 即 Boolean, Byte, Character, Short, Integer, Long, Float, or Double. * * @param clazz the class to check * 要检查的类 * * @return whether the given class is a primitive wrapper class * 给定的类是否为基础类型包装类 */ public static boolean isPrimitiveWrapper(final Class clazz) { if (clazz == null) { throw new IllegalArgumentException("Class must not be null"); } return PRIMITIVE_WRAPPER_TYPE_MAP.containsKey(clazz); } /** *

Check if the given class is a primitive or primitive wrapper class.

* * a primitive (i.e. boolean, byte, char, short, int, long, float, or double) * or a primitive wrapper (i.e. Boolean, Byte, Character, Short, Integer, Long, Float, or Double) * *

检查给定的类是否是基础类型或基础类型包装类。

* * 即基础类型(boolean, byte, char, short, int, long, float, double) * 或者包装类(Boolean, Byte, Character, Short, Integer, Long, Float, Double)。 * * * @param clazz the class to check * 要检查的类 * * @return whether the given class is a primitive or primitive wrapper class * 给定的类是否为基础类型或基础类型包装类 */ public static boolean isPrimitiveOrWrapper(final Class clazz) { if (clazz == null) { throw new IllegalArgumentException("Class must not be null"); } return (clazz.isPrimitive() || isPrimitiveWrapper(clazz)); } /** *

Check if the given class represents an array of primitives.

* i.e. Boolean, Byte, Character, Short, Integer, Long, Float, or Double. *

检查给定的类是否表示基础类型数组。

* 即 Boolean, Byte, Character, Short, Integer, Long, Float, Double. * * @param clazz the class to check * 要检查的类 * * @return whether the given class is a primitive array class * 给定的类是否为基础类型数组 */ public static boolean isPrimitiveArray(final Class clazz) { if (clazz == null) { throw new IllegalArgumentException("Class must not be null"); } return (clazz.isArray() && clazz.getComponentType().isPrimitive()); } /** *

Check if the given class represents an array of primitive wrappers.

* i.e. Boolean, Byte, Character, Short, Integer, Long, Float, or Double. *

检查给定的类是否表示基础类型包装类数组。

* 即 Boolean, Byte, Character, Short, Integer, Long, Float, Double. * * @param clazz the class to check * 要检查的类 * * @return whether the given class is a primitive wrapper array class * 给定的类是否为基础类型包装类数组 */ public static boolean isPrimitiveWrapperArray(final Class clazz) { if (clazz == null) { throw new IllegalArgumentException("Class must not be null"); } return (clazz.isArray() && isPrimitiveWrapper(clazz.getComponentType())); } /** *

Check if the right-hand side type may be assigned to the left-hand side type.

*

检查给定的检查类是目标类的子类或实现类

* * @param targetType the target type * 目标类 * @param checkType the value type that should be assigned to the target type * 目标类的子类或实现类 * * @return true if the target type is assignable from the value type, false for otherwise. * 检查类是目标类的子类或实现类,则返回true;否则返回false */ public static boolean isAssignable(final Class targetType, final Class checkType) { if (targetType == null) { throw new IllegalArgumentException("Target type must not be null"); } if (checkType == null) { throw new IllegalArgumentException("Check type must not be null"); } return (targetType.isAssignableFrom(checkType) || targetType.equals(PRIMITIVE_WRAPPER_TYPE_MAP.get(checkType))); } /** *

Determine if the given type is assignable from the given value.

*

确定给定的值是目标类的子类或实现类

* * @param type the target type * 目标类 * @param value the given value * 给定值 * * @return true if the given value is assignable from the given type, false for otherwise. * 给定的值是目标类的子类或实现类,则返回true;否则返回false */ public static boolean isAssignableValue(final Class type, final Object value) { if (type == null) { throw new IllegalArgumentException("Type must not be null"); } return (value != null ? isAssignable(type, value.getClass()) : !type.isPrimitive()); } /** *

Convert a "/"-based resource path to a "."-based fully qualified class name.

*

将基于“/”的资源路径转换为基于“.”的完全限定类名。

* * @param resourcePath the resource path pointing to a class * 指向类的资源路径 * * @return the corresponding fully qualified class name. * 相应的完全限定类名 */ public static String resourcePathToClassName(final String resourcePath) { return resourcePath.replace(Globals.DEFAULT_RESOURCE_SEPARATOR, Globals.DEFAULT_PACKAGE_SEPARATOR); } /** *

Convert a "."-based fully qualified class name to a "/"-based resource path.

*

将基于“.”的完全限定类名转换为基于“/”的资源路径。

* * @param className the fully qualified class name * 完全限定的类名 * * @return the corresponding resource path, pointing to the class. * 对应指向类的资源路径 */ public static String classNameToResourcePath(String className) { return className.replace(Globals.DEFAULT_PACKAGE_SEPARATOR, Globals.DEFAULT_RESOURCE_SEPARATOR) + CLASS_FILE_SUFFIX; } /** *

Return a path suitable for use with ClassLoader.getResource.

* * Also suitable for use with Class.getResource by prepending a * slash ('/') to the return value. Built by taking the package of the specified * class file, converting all dots ('.') to slashes ('/'), adding a trailing slash * if necessary, and concatenating the specified resource name to this. * As such, this function may be used to build a path suitable for * loading a resource file that is in the same package as a class file. * *

返回适用于 ClassLoader.getResource 的路径。

* * 也适合与 Class.getResource 一起使用,方法是在返回值前添加斜杠 ('/')。通过获取指定类文件的包, * 将所有点(“.”)转换为斜杠(“/”),根据需要添加尾部斜杠,并将指定的资源名称连接到此来构建。 * 因此,该函数可用于构建适合加载与类文件位于同一包中的资源文件的路径。 * * @see java.lang.ClassLoader#getResource(String) * @see java.lang.Class#getResource(String) * * @param clazz the Class whose package will be used as the base * 其包将用作基础的类 * @param resourceName the resource name to append. A leading slash is optional. * 要附加的资源名称。前导斜杠是可选的。 * * @return the built-up resource path * 构建的资源路径 */ public static String addResourcePathToPackagePath(final Class clazz, final String resourceName) { if (resourceName == null) { throw new IllegalArgumentException("Resource name must not be null"); } StringBuilder stringBuilder = new StringBuilder(classPackageAsResourcePath(clazz)); if (!resourceName.startsWith(Character.toString(Globals.DEFAULT_RESOURCE_SEPARATOR))) { stringBuilder.append(Globals.DEFAULT_RESOURCE_SEPARATOR); } stringBuilder.append(resourceName); return stringBuilder.toString(); } /** *

Given an input class object, return a string which consists of the class's package name as a pathname.

* * i.e., all dots ('.') are replaced by slashes ('/'). Neither a leading nor trailing slash is added. * The result could be concatenated with a slash and the name of a resource, and fed directly * to ClassLoader.getResource(). For it to be fed to Class.getResource instead, * a leading slash would also have to be prepended to the returned value. * *

给定一个输入类对象,返回一个由类的包名作为路径名组成的字符串。

* * 即,所有点('.')都被斜杠('/')替换。不添加前导斜杠或尾随斜杠。结果可以与斜杠和资源名称连接起来, * 并直接提供给 ClassLoader.getResource()。为了将其提供给 Class.getResource, * 还必须在返回值前面添加一个前导斜杠。 * * @see java.lang.ClassLoader#getResource(String) * @see java.lang.Class#getResource(String) * * @param clazz the input class. A null value or the default (empty) package will result in an empty string ("") being returned. * 输入类。 null 值或默认(空)包将导致返回空字符串 ("")。 * * @return a path which represents the package name * 代表包名称的路径 */ public static String classPackageAsResourcePath(final Class clazz) { if (clazz == null) { return Globals.DEFAULT_VALUE_STRING; } String className = clazz.getName(); int packageEndIndex = className.lastIndexOf(Globals.DEFAULT_PACKAGE_SEPARATOR); if (packageEndIndex == -1) { return Globals.DEFAULT_VALUE_STRING; } String packageName = className.substring(0, packageEndIndex); return packageName.replace(Globals.DEFAULT_PACKAGE_SEPARATOR, Globals.DEFAULT_RESOURCE_SEPARATOR); } /** *

Check given field name was exists field in target class

*

检查给定的字段名称是否存在于目标类中

* * @param clazz Target class instance * 目标类实例 * @param name the name of the field * 字段名称 * * @return the field object exists results * 字段对象存在结果 */ public static boolean existsField(final Class clazz, final String name) { return ReflectionUtils.findField(clazz, name) != null; } /** *

* Return all interfaces that the given instance implements as arrays, * including ones implemented by superclasses. *

*

返回给定实例作为数组实现的所有接口,包括由超类实现的接口。

* * @param instance the instance to analyze for interfaces * 用于分析接口的实例 * * @return all interfaces that the given instance implements as arrays * 给定实例作为数组实现的所有接口 */ public static Class[] getAllInterfaces(final Object instance) { if (instance == null) { throw new IllegalArgumentException("Instance must not be null"); } return getAllInterfacesForClass(instance.getClass()); } /** *

Return all interfaces that the given class implements as arrays, including ones implemented by superclasses.

* If the class itself is an interface, it gets returned as sole interface. *

返回给定类作为数组实现的所有接口,包括由超类实现的接口。

* 如果类本身是一个接口,它将作为唯一接口返回。 * * @param clazz the class to analyze for interfaces * 用于分析接口的类 * * @return all interfaces that the given instance implements as arrays * 给定实例作为数组实现的所有接口 */ public static Class[] getAllInterfacesForClass(final Class clazz) { return getAllInterfacesForClass(clazz, null); } /** *

Return all interfaces that the given class implements as arrays, including ones implemented by superclasses.

* If the class itself is an interface, it gets returned as sole interface. *

返回给定类作为数组实现的所有接口,包括由超类实现的接口。

* 如果类本身是一个接口,它将作为唯一接口返回。 * * @param clazz the class to analyze for interfaces * 用于分析接口的类 * @param classLoader the ClassLoader that the interfaces need to be visible in (maybe null when accepting all declared interfaces) * 接口需要在其中可见的类加载器(如果为null,则接受所有声明的接口) * * @return all interfaces that the given instance implements as arrays * 给定实例作为数组实现的所有接口 */ public static Class[] getAllInterfacesForClass(final Class clazz, final ClassLoader classLoader) { if (clazz == null || clazz.isInterface()) { return new Class[] {clazz}; } List> interfaces = new ArrayList<>(); if (clazz.getSuperclass() != null) { List.of(getAllInterfacesForClass(clazz.getSuperclass(), classLoader)) .forEach(interfaceClass -> { if (!CollectionUtils.contains(interfaces, interfaceClass)) { interfaces.add(interfaceClass); } }); } Stream.of(clazz.getInterfaces()) .filter(interfaceClass -> !CollectionUtils.contains(interfaces, interfaceClass) && (classLoader == null || isVisible(interfaceClass, classLoader))) .forEach(interfaces::add); return interfaces.toArray(new Class[0]); } /** *

Check whether the given class is visible in the given ClassLoader.

*

检查给定的类在给定的类加载器中是否可见。

* * @param clazz the class to check (typically an interface) * 要检查的类(通常是接口) * @param classLoader the ClassLoader to check against (maybe null in which case this method will always return Boolean.TRUE) * 要检查的类加载器(也许 null 在这种情况下,此方法将始终返回 Boolean.TRUE * * @return class is visible * 类可见 */ public static boolean isVisible(final Class clazz, final ClassLoader classLoader) { if (classLoader == null) { return Boolean.TRUE; } try { Class actualClass = classLoader.loadClass(clazz.getName()); return (clazz == actualClass); // Else: different interface class found... } catch (ClassNotFoundException ex) { // No interface class found... return Boolean.FALSE; } } /** *

Parse component type from given class.

*

从给定类中解析组件类型。

* * @param clazz Class instance * 类实例 * * @return Parsed component type or null if not a list or array * 解析的组件类型,如果不是列表或数组则为 null */ public static Class componentType(final Class clazz) { if (clazz.isArray()) { return clazz.getComponentType(); } else if (Collection.class.isAssignableFrom(clazz)) { return (Class) ((ParameterizedType) clazz.getGenericInterfaces()[0]).getActualTypeArguments()[0]; } return clazz; } /** *

Build a nice qualified name for an array: component type class name + "[]".

*

为数组建立一个好的限定名称:组件类型类名+“[]”。

* * @param clazz the array class * 数组类 * * @return a qualified name for the array class * 数组类的限定名称 */ private static String getQualifiedNameForArray(final Class clazz) { Class currentClass = clazz; StringBuilder buffer = new StringBuilder(); while (currentClass.isArray()) { currentClass = currentClass.getComponentType(); buffer.append(ClassUtils.ARRAY_SUFFIX); } buffer.insert(0, currentClass.getName()); return buffer.toString(); } }