diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/reflect/ClassUtil.java b/hutool-core/src/main/java/org/dromara/hutool/core/reflect/ClassUtil.java index 4ea977c3e..994775534 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/reflect/ClassUtil.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/reflect/ClassUtil.java @@ -17,6 +17,7 @@ import org.dromara.hutool.core.bean.NullWrapperBean; import org.dromara.hutool.core.classloader.ClassLoaderUtil; import org.dromara.hutool.core.convert.BasicType; import org.dromara.hutool.core.exception.HutoolException; +import org.dromara.hutool.core.func.PredicateUtil; import org.dromara.hutool.core.io.file.FileUtil; import org.dromara.hutool.core.io.resource.ResourceUtil; import org.dromara.hutool.core.net.url.UrlDecoder; @@ -737,38 +738,6 @@ public class ClassUtil { } } - /** - * 尝试转换并加载内部类,例如java.lang.Thread.State =》java.lang.Thread$State - * - * @param name 类名 - * @param classLoader {@link ClassLoader},{@code null} 则使用系统默认ClassLoader - * @param isInitialized 是否初始化类(调用static模块内容和初始化static属性) - * @return 类名对应的类,未找到返回{@code null} - */ - private static Class forNameInnerClass(String name, final boolean isInitialized, final ClassLoader classLoader) { - // 尝试获取内部类,例如java.lang.Thread.State =》java.lang.Thread$State - int lastDotIndex = name.lastIndexOf(PACKAGE_SEPARATOR); - Class clazz = null; - while (lastDotIndex > 0) {// 类与内部类的分隔符不能在第一位,因此>0 - if (!Character.isUpperCase(name.charAt(lastDotIndex + 1))) { - // 类名必须大写,非大写的类名跳过 - break; - } - name = name.substring(0, lastDotIndex) + INNER_CLASS_SEPARATOR + name.substring(lastDotIndex + 1); - try { - clazz = Class.forName(name, isInitialized, classLoader); - break; - } catch (final ClassNotFoundException ignore) { - //ignore - } - - // 继续向前替换.为$ - lastDotIndex = name.lastIndexOf(PACKAGE_SEPARATOR); - } - return clazz; - } - - /** * 获取指定类的所有父类,结果不包括指定类本身
* 如果无父类,返回一个空的列表 @@ -813,7 +782,7 @@ public class ClassUtil { */ public static void traverseTypeHierarchyWhile( final Class root, final Predicate> terminator) { - traverseTypeHierarchyWhile(root, t -> true, terminator); + traverseTypeHierarchyWhile(root, PredicateUtil.alwaysTrue(), terminator); } /** @@ -858,13 +827,50 @@ public class ClassUtil { EasyStream.iterateHierarchies(root, function, filter).exec(); } - private static Set> getNextTypeHierarchies(final Class t) { + /** + * 尝试转换并加载内部类,例如java.lang.Thread.State =》java.lang.Thread$State + * + * @param name 类名 + * @param classLoader {@link ClassLoader},{@code null} 则使用系统默认ClassLoader + * @param isInitialized 是否初始化类(调用static模块内容和初始化static属性) + * @return 类名对应的类,未找到返回{@code null} + */ + private static Class forNameInnerClass(String name, final boolean isInitialized, final ClassLoader classLoader) { + // 尝试获取内部类,例如java.lang.Thread.State =》java.lang.Thread$State + int lastDotIndex = name.lastIndexOf(PACKAGE_SEPARATOR); + Class clazz = null; + while (lastDotIndex > 0) {// 类与内部类的分隔符不能在第一位,因此>0 + if (!Character.isUpperCase(name.charAt(lastDotIndex + 1))) { + // 类名必须大写,非大写的类名跳过 + break; + } + name = name.substring(0, lastDotIndex) + INNER_CLASS_SEPARATOR + name.substring(lastDotIndex + 1); + try { + clazz = Class.forName(name, isInitialized, classLoader); + break; + } catch (final ClassNotFoundException ignore) { + //ignore + } + + // 继续向前替换.为$ + lastDotIndex = name.lastIndexOf(PACKAGE_SEPARATOR); + } + return clazz; + } + + /** + * 获取指定类的父类和所有接口 + * + * @param clazz 类 + * @return 类的父类和所有接口 + */ + private static Set> getNextTypeHierarchies(final Class clazz) { final Set> next = new LinkedHashSet<>(); - final Class superclass = t.getSuperclass(); + final Class superclass = clazz.getSuperclass(); if (Objects.nonNull(superclass)) { next.add(superclass); } - next.addAll(Arrays.asList(t.getInterfaces())); + next.addAll(Arrays.asList(clazz.getInterfaces())); return next; } } diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/reflect/method/MethodReflect.java b/hutool-core/src/main/java/org/dromara/hutool/core/reflect/method/MethodReflect.java new file mode 100644 index 000000000..aace3e633 --- /dev/null +++ b/hutool-core/src/main/java/org/dromara/hutool/core/reflect/method/MethodReflect.java @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2024. looly(loolly@aliyun.com) + * Hutool is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * https://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +package org.dromara.hutool.core.reflect.method; + +import org.dromara.hutool.core.array.ArrayUtil; +import org.dromara.hutool.core.collection.set.UniqueKeySet; +import org.dromara.hutool.core.lang.Assert; +import org.dromara.hutool.core.reflect.ModifierUtil; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.function.Predicate; + +/** + * 方法反射相关操作类。 + * + * @author Looly + * @since 6.0.0 + */ +public class MethodReflect { + + /** + * 获取反射对象 + * + * @param clazz 类 + * @return MethodReflect + */ + public static MethodReflect of(final Class clazz) { + return new MethodReflect(clazz); + } + + private final Class clazz; + private volatile Method[] publicMethods; + private volatile Method[] declaredMethods; + private volatile Method[] allMethods; + + /** + * 构造 + * + * @param clazz 类 + */ + public MethodReflect(final Class clazz) { + this.clazz = Assert.notNull(clazz); + } + + /** + * 获取当前类 + * + * @return 当前类 + */ + public Class getClazz() { + return clazz; + } + + /** + * 清空缓存 + */ + synchronized public void clearCaches() { + publicMethods = null; + declaredMethods = null; + allMethods = null; + } + + // region ----- getMathods + /** + * 获取当前类及父类的所有公共方法,等同于{@link Class#getMethods()} + * + * @param predicate 方法过滤器,{@code null}表示无过滤 + * @return 当前类及父类的所有公共方法 + */ + public Method[] getPublicMethods(final Predicate predicate) { + if (null == publicMethods) { + synchronized (MethodReflect.class) { + if (null == publicMethods) { + publicMethods = clazz.getMethods(); + } + } + } + return ArrayUtil.filter(publicMethods, predicate); + } + + /** + * 获取当前类直接声明的所有方法,等同于{@link Class#getDeclaredMethods()} + * + * @param predicate 方法过滤器,{@code null}表示无过滤 + * @return 当前类及父类的所有公共方法 + */ + public Method[] getDeclaredMethods(final Predicate predicate) { + if (null == declaredMethods) { + synchronized (MethodReflect.class) { + if (null == declaredMethods) { + declaredMethods = clazz.getDeclaredMethods(); + } + } + } + return ArrayUtil.filter(declaredMethods, predicate); + } + + /** + *

获取当前类层级结构中的所有方法。
+ * 等同于按广度优先遍历类及其所有父类与接口,并依次调用{@link Class#getDeclaredMethods()}。
+ * 返回的方法排序规则如下: + *

    + *
  • 离{@code type}距离越近,则顺序越靠前;
  • + *
  • 与{@code type}距离相同,直接实现的接口方法优先于父类方法;
  • + *
  • 与{@code type}距离相同的接口,则顺序遵循接口在{@link Class#getInterfaces()}的顺序;
  • + *
+ * + * @param predicate 方法过滤器,{@code null}表示无过滤 + * @return 当前类及父类的所有公共方法 + */ + public Method[] getAllMethods(final Predicate predicate) { + if (null == allMethods) { + synchronized (MethodReflect.class) { + if (null == allMethods) { + allMethods = getMethodsDirectly(true, true); + } + } + } + return ArrayUtil.filter(allMethods, predicate); + } + + /** + * 获得一个类中所有方法列表,直接反射获取,无缓存
+ * 接口获取方法和默认方法,获取的方法包括: + *
    + *
  • 本类中的所有方法(包括static方法)
  • + *
  • 父类中的所有方法(包括static方法)
  • + *
  • Object中(包括static方法)
  • + *
+ * + * @param withSupers 是否包括父类或接口的方法列表 + * @param withMethodFromObject 是否包括Object中的方法 + * @return 方法列表 + * @throws SecurityException 安全检查异常 + */ + public Method[] getMethodsDirectly(final boolean withSupers, final boolean withMethodFromObject) throws SecurityException { + final Class clazz = this.clazz; + + if (clazz.isInterface()) { + // 对于接口,直接调用Class.getMethods方法获取所有方法,因为接口都是public方法 + return withSupers ? clazz.getMethods() : clazz.getDeclaredMethods(); + } + + final UniqueKeySet result = new UniqueKeySet<>(true, MethodReflect::getUniqueKey); + Class searchType = clazz; + while (searchType != null) { + if (!withMethodFromObject && Object.class == searchType) { + break; + } + // 本类所有方法 + result.addAllIfAbsent(Arrays.asList(searchType.getDeclaredMethods())); + // 实现接口的所有默认方法 + result.addAllIfAbsent(getDefaultMethodsFromInterface(searchType)); + + + searchType = (withSupers && !searchType.isInterface()) ? searchType.getSuperclass() : null; + } + + return result.toArray(new Method[0]); + } + // endregion + + /** + * 获取方法的唯一键,结构为: + *
+	 *     返回类型#方法名:参数1类型,参数2类型...
+	 * 
+ * + * @param method 方法 + * @return 方法唯一键 + */ + private static String getUniqueKey(final Method method) { + final StringBuilder sb = new StringBuilder(); + sb.append(method.getReturnType().getName()).append('#'); + sb.append(method.getName()); + final Class[] parameters = method.getParameterTypes(); + for (int i = 0; i < parameters.length; i++) { + if (i == 0) { + sb.append(':'); + } else { + sb.append(','); + } + sb.append(parameters[i].getName()); + } + return sb.toString(); + } + + /** + * 获取类对应接口中的非抽象方法(default方法) + * + * @param clazz 类 + * @return 方法列表 + */ + private static List getDefaultMethodsFromInterface(final Class clazz) { + final List result = new ArrayList<>(); + for (final Class ifc : clazz.getInterfaces()) { + for (final Method m : ifc.getMethods()) { + if (!ModifierUtil.isAbstract(m)) { + result.add(m); + } + } + } + return result; + } +} diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/reflect/method/MethodScanner2.java b/hutool-core/src/main/java/org/dromara/hutool/core/reflect/method/MethodScanner2.java index f17b68744..cc21bb9aa 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/reflect/method/MethodScanner2.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/reflect/method/MethodScanner2.java @@ -140,8 +140,8 @@ public class MethodScanner2 { return EMPTY_METHODS; } final List methods = new ArrayList<>(); - ClassUtil.traverseTypeHierarchyWhile(type, t -> { - methods.addAll(Arrays.asList(getDeclaredMethods(t))); + ClassUtil.traverseTypeHierarchyWhile(type, clazz -> { + methods.addAll(Arrays.asList(getDeclaredMethods(clazz))); return true; }); return methods.isEmpty() ? EMPTY_METHODS : methods.toArray(new Method[0]); diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/reflect/method/MethodUtil.java b/hutool-core/src/main/java/org/dromara/hutool/core/reflect/method/MethodUtil.java index 39039c05f..78d2fc372 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/reflect/method/MethodUtil.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/reflect/method/MethodUtil.java @@ -15,8 +15,6 @@ package org.dromara.hutool.core.reflect.method; import org.dromara.hutool.core.array.ArrayUtil; import org.dromara.hutool.core.bean.NullWrapperBean; import org.dromara.hutool.core.classloader.ClassLoaderUtil; -import org.dromara.hutool.core.collection.set.SetUtil; -import org.dromara.hutool.core.collection.set.UniqueKeySet; import org.dromara.hutool.core.convert.Convert; import org.dromara.hutool.core.exception.ExceptionUtil; import org.dromara.hutool.core.exception.HutoolException; @@ -26,31 +24,29 @@ import org.dromara.hutool.core.map.reference.WeakConcurrentMap; import org.dromara.hutool.core.reflect.ClassUtil; import org.dromara.hutool.core.reflect.ConstructorUtil; import org.dromara.hutool.core.reflect.ModifierUtil; +import org.dromara.hutool.core.stream.StreamUtil; import org.dromara.hutool.core.text.StrUtil; import org.dromara.hutool.core.util.BooleanUtil; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.util.*; +import java.util.Set; import java.util.function.Predicate; +import java.util.stream.Collectors; /** * 反射中{@link Method}相关工具类,包括方法获取和方法执行
- * TODO 与commons-beanutils相比,Hutool缓存某个类的所有方法,而commons缓存单个方法,须性能测试哪个更加合理。 * * @author looly */ public class MethodUtil { + /** * 方法缓存 */ - private static final WeakConcurrentMap, Method[]> METHODS_CACHE = new WeakConcurrentMap<>(); - /** - * 直接声明的方法缓存 - */ - private static final WeakConcurrentMap, Method[]> DECLARED_METHODS_CACHE = new WeakConcurrentMap<>(); + private static final WeakConcurrentMap, MethodReflect> METHODS_CACHE = new WeakConcurrentMap<>(); - // --------------------------------------------------------------------------------------------------------- method + // region ----- getMethods /** * 获得指定类本类及其父类中的Public方法名
@@ -60,85 +56,34 @@ public class MethodUtil { * @return 方法名Set */ public static Set getPublicMethodNames(final Class clazz) { - final HashSet methodSet = new HashSet<>(); - final Method[] methodArray = getPublicMethods(clazz); - if (ArrayUtil.isNotEmpty(methodArray)) { - for (final Method method : methodArray) { - methodSet.add(method.getName()); - } - } - return methodSet; - } - - /** - * 获得本类及其父类所有Public方法 - * - * @param clazz 查找方法的类 - * @return 过滤后的方法列表 - */ - public static Method[] getPublicMethods(final Class clazz) { - return null == clazz ? null : clazz.getMethods(); - } - - /** - * 获得指定类过滤后的Public方法列表
- * - * @param clazz 查找方法的类 - * @param predicate 过滤器,{@link Predicate#test(Object)}为{@code true}保留,null表示保留全部 - * @return 过滤后的方法数组 - */ - public static Method[] getPublicMethods(final Class clazz, final Predicate predicate) { - if (null == clazz) { - return null; - } - - final Method[] methods = getPublicMethods(clazz); - if (null == predicate) { - return methods; - } - - return ArrayUtil.filter(methods, predicate); - } - - /** - * 获得指定类过滤后的Public方法列表 - * - * @param clazz 查找方法的类 - * @param excludeMethods 不包括的方法 - * @return 过滤后的方法列表 - */ - public static Method[] getPublicMethods(final Class clazz, final Method... excludeMethods) { - final HashSet excludeMethodSet = SetUtil.of(excludeMethods); - return getPublicMethods(clazz, method -> !excludeMethodSet.contains(method)); - } - - /** - * 获得指定类过滤后的Public方法列表 - * - * @param clazz 查找方法的类 - * @param excludeMethodNames 不包括的方法名列表 - * @return 过滤后的方法数组 - */ - public static Method[] getPublicMethods(final Class clazz, final String... excludeMethodNames) { - final HashSet excludeMethodNameSet = SetUtil.of(excludeMethodNames); - return getPublicMethods(clazz, method -> !excludeMethodNameSet.contains(method.getName())); + return StreamUtil.of(getPublicMethods(clazz)) + .map(Method::getName) + .collect(Collectors.toSet()); } /** * 查找指定Public方法 如果找不到对应的方法或方法不为public的则返回{@code null} * * @param clazz 类 + * @param ignoreCase 是否忽略大小写 * @param methodName 方法名 * @param paramTypes 参数类型 * @return 方法 * @throws SecurityException 无权访问抛出异常 */ - public static Method getPublicMethod(final Class clazz, final String methodName, final Class... paramTypes) throws SecurityException { - try { - return clazz.getMethod(methodName, paramTypes); - } catch (final NoSuchMethodException ex) { + public static Method getPublicMethod(final Class clazz, final boolean ignoreCase, final String methodName, final Class... paramTypes) throws SecurityException { + if (null == clazz || StrUtil.isBlank(methodName)) { return null; } + + final Method[] methods = getPublicMethods(clazz, method -> + StrUtil.equals(methodName, method.getName(), ignoreCase) + && ClassUtil.isAllAssignableFrom(method.getParameterTypes(), paramTypes) + //排除桥接方法,pr#1965@Github + //排除协变桥接方法,pr#1965@Github + && (method.getReturnType().isAssignableFrom(method.getReturnType()))); + + return ArrayUtil.isEmpty(methods) ? null : methods[0]; } /** @@ -214,20 +159,14 @@ public class MethodUtil { return null; } - Method res = null; - final Method[] methods = getMethods(clazz); - if (ArrayUtil.isNotEmpty(methods)) { - for (final Method method : methods) { - if (StrUtil.equals(methodName, method.getName(), ignoreCase) - && ClassUtil.isAllAssignableFrom(method.getParameterTypes(), paramTypes) - //排除桥接方法,pr#1965@Github - //排除协变桥接方法,pr#1965@Github - && (res == null || res.getReturnType().isAssignableFrom(method.getReturnType()))) { - res = method; - } - } - } - return res; + final Method[] methods = getMethods(clazz, method -> + StrUtil.equals(methodName, method.getName(), ignoreCase) + && ClassUtil.isAllAssignableFrom(method.getParameterTypes(), paramTypes) + //排除桥接方法,pr#1965@Github + //排除协变桥接方法,pr#1965@Github + && (method.getReturnType().isAssignableFrom(method.getReturnType()))); + + return ArrayUtil.isEmpty(methods) ? null : methods[0]; } /** @@ -283,18 +222,10 @@ public class MethodUtil { return null; } - Method res = null; - final Method[] methods = getMethods(clazz); - if (ArrayUtil.isNotEmpty(methods)) { - for (final Method method : methods) { - if (StrUtil.equals(methodName, method.getName(), ignoreCase) - //排除协变桥接方法,pr#1965@Github - && (res == null || res.getReturnType().isAssignableFrom(method.getReturnType()))) { - res = method; - } - } - } - return res; + final Method[] methods = getMethods(clazz, (method -> + StrUtil.equals(methodName, method.getName(), ignoreCase) && (method.getReturnType().isAssignableFrom(method.getReturnType())))); + + return ArrayUtil.isEmpty(methods) ? null : methods[0]; } /** @@ -306,55 +237,80 @@ public class MethodUtil { * @throws SecurityException 安全异常 */ public static Set getMethodNames(final Class clazz) throws SecurityException { - final HashSet methodSet = new HashSet<>(); - final Method[] methods = getMethods(clazz); - for (final Method method : methods) { - methodSet.add(method.getName()); - } - return methodSet; - } - - /** - * 获得指定类过滤后的方法列表 - * - * @param clazz 查找方法的类 - * @param predicate 过滤器,{@link Predicate#test(Object)}为{@code true}保留,null表示全部保留。 - * @return 过滤后的方法列表 - * @throws SecurityException 安全异常 - */ - public static Method[] getMethods(final Class clazz, final Predicate predicate) throws SecurityException { - if (null == clazz) { - return null; - } - return ArrayUtil.filter(getMethods(clazz), predicate); + return StreamUtil.of(getMethods(clazz, null)) + .map(Method::getName) + .collect(Collectors.toSet()); } /** * 获得一个类中所有方法列表,包括其父类中的方法 * - * @param beanClass 类,非{@code null} + * @param clazz 类,非{@code null} * @return 方法列表 * @throws SecurityException 安全检查异常 */ - public static Method[] getMethods(final Class beanClass) throws SecurityException { - Assert.notNull(beanClass); - return METHODS_CACHE.computeIfAbsent(beanClass, - (key) -> getMethodsDirectly(beanClass, true, true)); + public static Method[] getMethods(final Class clazz) throws SecurityException { + return getMethods(clazz, null); + } + + /** + * 获得一个类中所有方法列表,包括其父类中的方法 + * + * @param clazz 类,非{@code null} + * @param predicate 方法过滤器,{@code null}表示无过滤 + * @return 方法列表 + * @throws SecurityException 安全检查异常 + */ + public static Method[] getMethods(final Class clazz, final Predicate predicate) throws SecurityException { + return METHODS_CACHE.computeIfAbsent(Assert.notNull(clazz), MethodReflect::of).getAllMethods(predicate); + } + + /** + * 获得本类及其父类所有Public方法 + * + * @param clazz 查找方法的类 + * @return 过滤后的方法列表 + */ + public static Method[] getPublicMethods(final Class clazz) { + return getPublicMethods(clazz, null); + } + + /** + * 获得本类及其父类所有Public方法 + * + * @param clazz 查找方法的类 + * @param predicate 方法过滤器,{@code null}表示无过滤 + * @return 过滤后的方法列表 + */ + public static Method[] getPublicMethods(final Class clazz, final Predicate predicate) { + return METHODS_CACHE.computeIfAbsent(Assert.notNull(clazz), MethodReflect::of).getPublicMethods(predicate); } /** * 获得类中所有直接声明方法,不包括其父类中的方法 * - * @param beanClass 类,非{@code null} + * @param clazz 类,非{@code null} * @return 方法列表 * @throws SecurityException 安全检查异常 */ - public static Method[] getDeclaredMethods(final Class beanClass) throws SecurityException { - Assert.notNull(beanClass); - return DECLARED_METHODS_CACHE.computeIfAbsent(beanClass, - key -> getMethodsDirectly(beanClass, false, Objects.equals(Object.class, beanClass))); + public static Method[] getDeclaredMethods(final Class clazz) throws SecurityException { + return getDeclaredMethods(clazz, null); } + /** + * 获得类中所有直接声明方法,不包括其父类中的方法 + * + * @param clazz 类,非{@code null} + * @param predicate 方法过滤器,{@code null}表示无过滤 + * @return 方法列表 + * @throws SecurityException 安全检查异常 + */ + public static Method[] getDeclaredMethods(final Class clazz, final Predicate predicate) throws SecurityException { + return METHODS_CACHE.computeIfAbsent(Assert.notNull(clazz), MethodReflect::of).getDeclaredMethods(predicate); + } + + // endregion + /** * 获得一个类中所有方法列表,直接反射获取,无缓存
* 接口获取方法和默认方法,获取的方法包括: @@ -371,27 +327,7 @@ public class MethodUtil { * @throws SecurityException 安全检查异常 */ public static Method[] getMethodsDirectly(final Class beanClass, final boolean withSupers, final boolean withMethodFromObject) throws SecurityException { - Assert.notNull(beanClass); - - if (beanClass.isInterface()) { - // 对于接口,直接调用Class.getMethods方法获取所有方法,因为接口都是public方法 - return withSupers ? beanClass.getMethods() : beanClass.getDeclaredMethods(); - } - - final UniqueKeySet result = new UniqueKeySet<>(true, MethodUtil::getUniqueKey); - Class searchType = beanClass; - while (searchType != null) { - if (!withMethodFromObject && Object.class == searchType) { - break; - } - result.addAllIfAbsent(Arrays.asList(searchType.getDeclaredMethods())); - result.addAllIfAbsent(getDefaultMethodsFromInterface(searchType)); - - - searchType = (withSupers && !searchType.isInterface()) ? searchType.getSuperclass() : null; - } - - return result.toArray(new Method[0]); + return MethodReflect.of(Assert.notNull(beanClass)).getMethodsDirectly(withSupers, withMethodFromObject); } /** @@ -477,7 +413,7 @@ public class MethodUtil { public static boolean isGetterOrSetter(final Method method, final boolean ignoreCase) { // 参数个数必须为1 final int parameterCount = method.getParameterCount(); - switch (parameterCount){ + switch (parameterCount) { case 0: return isGetter(method, ignoreCase); case 1: @@ -562,7 +498,7 @@ public class MethodUtil { return name.startsWith("get"); } - // --------------------------------------------------------------------------------------------------------- invoke + // region ----- invoke /** * 执行静态方法 @@ -632,9 +568,9 @@ public class MethodUtil { */ @SuppressWarnings("unchecked") public static T invoke(final Object obj, final Method method, final Object... args) throws HutoolException { - try{ + try { return MethodHandleUtil.invoke(obj, method, args); - } catch (final Exception e){ + } catch (final Exception e) { // 传统反射方式执行方法 try { return (T) method.invoke(ModifierUtil.isStatic(method) ? null : obj, actualArgs(method, args)); @@ -676,7 +612,7 @@ public class MethodUtil { * * @param 对象类型 * @param classNameWithMethodName 类名和方法名表达式,类名与方法名用{@code .}或{@code #}连接 - * 例如:org.dromara.hutool.core.text.StrUtil.isEmpty 或 org.dromara.hutool.core.text.StrUtil#isEmpty + * 例如:org.dromara.hutool.core.text.StrUtil.isEmpty 或 org.dromara.hutool.core.text.StrUtil#isEmpty * @param args 参数,必须严格对应指定方法的参数类型和数量 * @return 返回结果 */ @@ -691,7 +627,7 @@ public class MethodUtil { * * @param 对象类型 * @param classNameWithMethodName 类名和方法名表达式, - * 例如:org.dromara.hutool.core.text.StrUtil#isEmpty或org.dromara.hutool.core.text.StrUtil.isEmpty + * 例如:org.dromara.hutool.core.text.StrUtil#isEmpty或org.dromara.hutool.core.text.StrUtil.isEmpty * @param isSingleton 是否为单例对象,如果此参数为false,每次执行方法时创建一个新对象 * @param args 参数,必须严格对应指定方法的参数类型和数量 * @return 返回结果 @@ -760,6 +696,8 @@ public class MethodUtil { } } + // endregion + /** * 检查用户传入参数: *
    @@ -776,7 +714,7 @@ public class MethodUtil { */ public static Object[] actualArgs(final Method method, final Object[] args) { final Class[] parameterTypes = method.getParameterTypes(); - if(1 == parameterTypes.length && parameterTypes[0].isArray()){ + if (1 == parameterTypes.length && parameterTypes[0].isArray()) { // 可变长参数,不做转换 return args; } @@ -804,46 +742,4 @@ public class MethodUtil { return actualArgs; } - /** - * 获取方法的唯一键,结构为: - *
    -	 *     返回类型#方法名:参数1类型,参数2类型...
    -	 * 
    - * - * @param method 方法 - * @return 方法唯一键 - */ - private static String getUniqueKey(final Method method) { - final StringBuilder sb = new StringBuilder(); - sb.append(method.getReturnType().getName()).append('#'); - sb.append(method.getName()); - final Class[] parameters = method.getParameterTypes(); - for (int i = 0; i < parameters.length; i++) { - if (i == 0) { - sb.append(':'); - } else { - sb.append(','); - } - sb.append(parameters[i].getName()); - } - return sb.toString(); - } - - /** - * 获取类对应接口中的非抽象方法(default方法) - * - * @param clazz 类 - * @return 方法列表 - */ - private static List getDefaultMethodsFromInterface(final Class clazz) { - final List result = new ArrayList<>(); - for (final Class ifc : clazz.getInterfaces()) { - for (final Method m : ifc.getMethods()) { - if (!ModifierUtil.isAbstract(m)) { - result.add(m); - } - } - } - return result; - } } diff --git a/hutool-core/src/test/java/org/dromara/hutool/core/reflect/MethodUtilTest.java b/hutool-core/src/test/java/org/dromara/hutool/core/reflect/MethodUtilTest.java index cc402ccda..cf6880c6a 100644 --- a/hutool-core/src/test/java/org/dromara/hutool/core/reflect/MethodUtilTest.java +++ b/hutool-core/src/test/java/org/dromara/hutool/core/reflect/MethodUtilTest.java @@ -180,14 +180,14 @@ public class MethodUtilTest { @Test public void getPublicMethod() { - final Method superPublicMethod = MethodUtil.getPublicMethod(ReflectUtilTest.TestSubClass.class, "publicMethod"); + final Method superPublicMethod = MethodUtil.getPublicMethod(ReflectUtilTest.TestSubClass.class, false, "publicMethod"); Assertions.assertNotNull(superPublicMethod); - final Method superPrivateMethod = MethodUtil.getPublicMethod(ReflectUtilTest.TestSubClass.class, "privateMethod"); + final Method superPrivateMethod = MethodUtil.getPublicMethod(ReflectUtilTest.TestSubClass.class, false, "privateMethod"); Assertions.assertNull(superPrivateMethod); - final Method publicMethod = MethodUtil.getPublicMethod(ReflectUtilTest.TestSubClass.class, "publicSubMethod"); + final Method publicMethod = MethodUtil.getPublicMethod(ReflectUtilTest.TestSubClass.class, false, "publicSubMethod"); Assertions.assertNotNull(publicMethod); - final Method privateMethod = MethodUtil.getPublicMethod(ReflectUtilTest.TestSubClass.class, "privateSubMethod"); + final Method privateMethod = MethodUtil.getPublicMethod(ReflectUtilTest.TestSubClass.class, false, "privateSubMethod"); Assertions.assertNull(privateMethod); } diff --git a/hutool-cron/src/main/java/org/dromara/hutool/cron/task/InvokeTask.java b/hutool-cron/src/main/java/org/dromara/hutool/cron/task/InvokeTask.java index 318f0f2f4..9e975585e 100644 --- a/hutool-cron/src/main/java/org/dromara/hutool/cron/task/InvokeTask.java +++ b/hutool-cron/src/main/java/org/dromara/hutool/cron/task/InvokeTask.java @@ -63,7 +63,7 @@ public class InvokeTask implements Task{ if(StrUtil.isBlank(methodName)) { throw new IllegalArgumentException("Method name is blank !"); } - this.method = MethodUtil.getPublicMethod(clazz, methodName); + this.method = MethodUtil.getPublicMethod(clazz, false, methodName); if(null == this.method) { throw new IllegalArgumentException("No method with name of [" + methodName + "] !"); }