add MethodReflect

This commit is contained in:
Looly
2024-05-14 17:37:38 +08:00
parent d4bb369443
commit a1f23fc22c
6 changed files with 366 additions and 246 deletions

View File

@@ -17,6 +17,7 @@ import org.dromara.hutool.core.bean.NullWrapperBean;
import org.dromara.hutool.core.classloader.ClassLoaderUtil; import org.dromara.hutool.core.classloader.ClassLoaderUtil;
import org.dromara.hutool.core.convert.BasicType; import org.dromara.hutool.core.convert.BasicType;
import org.dromara.hutool.core.exception.HutoolException; 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.file.FileUtil;
import org.dromara.hutool.core.io.resource.ResourceUtil; import org.dromara.hutool.core.io.resource.ResourceUtil;
import org.dromara.hutool.core.net.url.UrlDecoder; 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;
}
/** /**
* 获取指定类的所有父类,结果不包括指定类本身<br> * 获取指定类的所有父类,结果不包括指定类本身<br>
* 如果无父类,返回一个空的列表 * 如果无父类,返回一个空的列表
@@ -813,7 +782,7 @@ public class ClassUtil {
*/ */
public static void traverseTypeHierarchyWhile( public static void traverseTypeHierarchyWhile(
final Class<?> root, final Predicate<Class<?>> terminator) { final Class<?> root, final Predicate<Class<?>> terminator) {
traverseTypeHierarchyWhile(root, t -> true, terminator); traverseTypeHierarchyWhile(root, PredicateUtil.alwaysTrue(), terminator);
} }
/** /**
@@ -858,13 +827,50 @@ public class ClassUtil {
EasyStream.iterateHierarchies(root, function, filter).exec(); EasyStream.iterateHierarchies(root, function, filter).exec();
} }
private static Set<Class<?>> 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<Class<?>> getNextTypeHierarchies(final Class<?> clazz) {
final Set<Class<?>> next = new LinkedHashSet<>(); final Set<Class<?>> next = new LinkedHashSet<>();
final Class<?> superclass = t.getSuperclass(); final Class<?> superclass = clazz.getSuperclass();
if (Objects.nonNull(superclass)) { if (Objects.nonNull(superclass)) {
next.add(superclass); next.add(superclass);
} }
next.addAll(Arrays.asList(t.getInterfaces())); next.addAll(Arrays.asList(clazz.getInterfaces()));
return next; return next;
} }
} }

View File

@@ -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<Method> 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<Method> predicate) {
if (null == declaredMethods) {
synchronized (MethodReflect.class) {
if (null == declaredMethods) {
declaredMethods = clazz.getDeclaredMethods();
}
}
}
return ArrayUtil.filter(declaredMethods, predicate);
}
/**
* <p>获取当前类层级结构中的所有方法。<br>
* 等同于按广度优先遍历类及其所有父类与接口,并依次调用{@link Class#getDeclaredMethods()}。<br>
* 返回的方法排序规则如下:
* <ul>
* <li>离{@code type}距离越近,则顺序越靠前;</li>
* <li>与{@code type}距离相同,直接实现的接口方法优先于父类方法;</li>
* <li>与{@code type}距离相同的接口,则顺序遵循接口在{@link Class#getInterfaces()}的顺序;</li>
* </ul>
*
* @param predicate 方法过滤器,{@code null}表示无过滤
* @return 当前类及父类的所有公共方法
*/
public Method[] getAllMethods(final Predicate<Method> predicate) {
if (null == allMethods) {
synchronized (MethodReflect.class) {
if (null == allMethods) {
allMethods = getMethodsDirectly(true, true);
}
}
}
return ArrayUtil.filter(allMethods, predicate);
}
/**
* 获得一个类中所有方法列表,直接反射获取,无缓存<br>
* 接口获取方法和默认方法,获取的方法包括:
* <ul>
* <li>本类中的所有方法包括static方法</li>
* <li>父类中的所有方法包括static方法</li>
* <li>Object中包括static方法</li>
* </ul>
*
* @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<String, Method> 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
/**
* 获取方法的唯一键,结构为:
* <pre>
* 返回类型#方法名:参数1类型,参数2类型...
* </pre>
*
* @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<Method> getDefaultMethodsFromInterface(final Class<?> clazz) {
final List<Method> result = new ArrayList<>();
for (final Class<?> ifc : clazz.getInterfaces()) {
for (final Method m : ifc.getMethods()) {
if (!ModifierUtil.isAbstract(m)) {
result.add(m);
}
}
}
return result;
}
}

View File

@@ -140,8 +140,8 @@ public class MethodScanner2 {
return EMPTY_METHODS; return EMPTY_METHODS;
} }
final List<Method> methods = new ArrayList<>(); final List<Method> methods = new ArrayList<>();
ClassUtil.traverseTypeHierarchyWhile(type, t -> { ClassUtil.traverseTypeHierarchyWhile(type, clazz -> {
methods.addAll(Arrays.asList(getDeclaredMethods(t))); methods.addAll(Arrays.asList(getDeclaredMethods(clazz)));
return true; return true;
}); });
return methods.isEmpty() ? EMPTY_METHODS : methods.toArray(new Method[0]); return methods.isEmpty() ? EMPTY_METHODS : methods.toArray(new Method[0]);

View File

@@ -15,8 +15,6 @@ package org.dromara.hutool.core.reflect.method;
import org.dromara.hutool.core.array.ArrayUtil; import org.dromara.hutool.core.array.ArrayUtil;
import org.dromara.hutool.core.bean.NullWrapperBean; import org.dromara.hutool.core.bean.NullWrapperBean;
import org.dromara.hutool.core.classloader.ClassLoaderUtil; 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.convert.Convert;
import org.dromara.hutool.core.exception.ExceptionUtil; import org.dromara.hutool.core.exception.ExceptionUtil;
import org.dromara.hutool.core.exception.HutoolException; 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.ClassUtil;
import org.dromara.hutool.core.reflect.ConstructorUtil; import org.dromara.hutool.core.reflect.ConstructorUtil;
import org.dromara.hutool.core.reflect.ModifierUtil; 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.text.StrUtil;
import org.dromara.hutool.core.util.BooleanUtil; import org.dromara.hutool.core.util.BooleanUtil;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.*; import java.util.Set;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.stream.Collectors;
/** /**
* 反射中{@link Method}相关工具类,包括方法获取和方法执行<br> * 反射中{@link Method}相关工具类,包括方法获取和方法执行<br>
* TODO 与commons-beanutils相比Hutool缓存某个类的所有方法而commons缓存单个方法须性能测试哪个更加合理。
* *
* @author looly * @author looly
*/ */
public class MethodUtil { public class MethodUtil {
/** /**
* 方法缓存 * 方法缓存
*/ */
private static final WeakConcurrentMap<Class<?>, Method[]> METHODS_CACHE = new WeakConcurrentMap<>(); private static final WeakConcurrentMap<Class<?>, MethodReflect> METHODS_CACHE = new WeakConcurrentMap<>();
/**
* 直接声明的方法缓存
*/
private static final WeakConcurrentMap<Class<?>, Method[]> DECLARED_METHODS_CACHE = new WeakConcurrentMap<>();
// --------------------------------------------------------------------------------------------------------- method // region ----- getMethods
/** /**
* 获得指定类本类及其父类中的Public方法名<br> * 获得指定类本类及其父类中的Public方法名<br>
@@ -60,85 +56,34 @@ public class MethodUtil {
* @return 方法名Set * @return 方法名Set
*/ */
public static Set<String> getPublicMethodNames(final Class<?> clazz) { public static Set<String> getPublicMethodNames(final Class<?> clazz) {
final HashSet<String> methodSet = new HashSet<>(); return StreamUtil.of(getPublicMethods(clazz))
final Method[] methodArray = getPublicMethods(clazz); .map(Method::getName)
if (ArrayUtil.isNotEmpty(methodArray)) { .collect(Collectors.toSet());
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方法列表<br>
*
* @param clazz 查找方法的类
* @param predicate 过滤器,{@link Predicate#test(Object)}为{@code true}保留null表示保留全部
* @return 过滤后的方法数组
*/
public static Method[] getPublicMethods(final Class<?> clazz, final Predicate<Method> 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<Method> 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<String> excludeMethodNameSet = SetUtil.of(excludeMethodNames);
return getPublicMethods(clazz, method -> !excludeMethodNameSet.contains(method.getName()));
} }
/** /**
* 查找指定Public方法 如果找不到对应的方法或方法不为public的则返回{@code null} * 查找指定Public方法 如果找不到对应的方法或方法不为public的则返回{@code null}
* *
* @param clazz 类 * @param clazz 类
* @param ignoreCase 是否忽略大小写
* @param methodName 方法名 * @param methodName 方法名
* @param paramTypes 参数类型 * @param paramTypes 参数类型
* @return 方法 * @return 方法
* @throws SecurityException 无权访问抛出异常 * @throws SecurityException 无权访问抛出异常
*/ */
public static Method getPublicMethod(final Class<?> clazz, final String methodName, final Class<?>... paramTypes) throws SecurityException { public static Method getPublicMethod(final Class<?> clazz, final boolean ignoreCase, final String methodName, final Class<?>... paramTypes) throws SecurityException {
try { if (null == clazz || StrUtil.isBlank(methodName)) {
return clazz.getMethod(methodName, paramTypes);
} catch (final NoSuchMethodException ex) {
return null; 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; return null;
} }
Method res = null; final Method[] methods = getMethods(clazz, method ->
final Method[] methods = getMethods(clazz); StrUtil.equals(methodName, method.getName(), ignoreCase)
if (ArrayUtil.isNotEmpty(methods)) {
for (final Method method : methods) {
if (StrUtil.equals(methodName, method.getName(), ignoreCase)
&& ClassUtil.isAllAssignableFrom(method.getParameterTypes(), paramTypes) && ClassUtil.isAllAssignableFrom(method.getParameterTypes(), paramTypes)
//排除桥接方法pr#1965@Github //排除桥接方法pr#1965@Github
//排除协变桥接方法pr#1965@Github //排除协变桥接方法pr#1965@Github
&& (res == null || res.getReturnType().isAssignableFrom(method.getReturnType()))) { && (method.getReturnType().isAssignableFrom(method.getReturnType())));
res = method;
} return ArrayUtil.isEmpty(methods) ? null : methods[0];
}
}
return res;
} }
/** /**
@@ -283,18 +222,10 @@ public class MethodUtil {
return null; return null;
} }
Method res = null; final Method[] methods = getMethods(clazz, (method ->
final Method[] methods = getMethods(clazz); StrUtil.equals(methodName, method.getName(), ignoreCase) && (method.getReturnType().isAssignableFrom(method.getReturnType()))));
if (ArrayUtil.isNotEmpty(methods)) {
for (final Method method : methods) { return ArrayUtil.isEmpty(methods) ? null : methods[0];
if (StrUtil.equals(methodName, method.getName(), ignoreCase)
//排除协变桥接方法pr#1965@Github
&& (res == null || res.getReturnType().isAssignableFrom(method.getReturnType()))) {
res = method;
}
}
}
return res;
} }
/** /**
@@ -306,55 +237,80 @@ public class MethodUtil {
* @throws SecurityException 安全异常 * @throws SecurityException 安全异常
*/ */
public static Set<String> getMethodNames(final Class<?> clazz) throws SecurityException { public static Set<String> getMethodNames(final Class<?> clazz) throws SecurityException {
final HashSet<String> methodSet = new HashSet<>(); return StreamUtil.of(getMethods(clazz, null))
final Method[] methods = getMethods(clazz); .map(Method::getName)
for (final Method method : methods) { .collect(Collectors.toSet());
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<Method> predicate) throws SecurityException {
if (null == clazz) {
return null;
}
return ArrayUtil.filter(getMethods(clazz), predicate);
} }
/** /**
* 获得一个类中所有方法列表,包括其父类中的方法 * 获得一个类中所有方法列表,包括其父类中的方法
* *
* @param beanClass 类,非{@code null} * @param clazz 类,非{@code null}
* @return 方法列表 * @return 方法列表
* @throws SecurityException 安全检查异常 * @throws SecurityException 安全检查异常
*/ */
public static Method[] getMethods(final Class<?> beanClass) throws SecurityException { public static Method[] getMethods(final Class<?> clazz) throws SecurityException {
Assert.notNull(beanClass); return getMethods(clazz, null);
return METHODS_CACHE.computeIfAbsent(beanClass, }
(key) -> getMethodsDirectly(beanClass, true, true));
/**
* 获得一个类中所有方法列表,包括其父类中的方法
*
* @param clazz 类,非{@code null}
* @param predicate 方法过滤器,{@code null}表示无过滤
* @return 方法列表
* @throws SecurityException 安全检查异常
*/
public static Method[] getMethods(final Class<?> clazz, final Predicate<Method> 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<Method> predicate) {
return METHODS_CACHE.computeIfAbsent(Assert.notNull(clazz), MethodReflect::of).getPublicMethods(predicate);
} }
/** /**
* 获得类中所有直接声明方法,不包括其父类中的方法 * 获得类中所有直接声明方法,不包括其父类中的方法
* *
* @param beanClass 类,非{@code null} * @param clazz 类,非{@code null}
* @return 方法列表 * @return 方法列表
* @throws SecurityException 安全检查异常 * @throws SecurityException 安全检查异常
*/ */
public static Method[] getDeclaredMethods(final Class<?> beanClass) throws SecurityException { public static Method[] getDeclaredMethods(final Class<?> clazz) throws SecurityException {
Assert.notNull(beanClass); return getDeclaredMethods(clazz, null);
return DECLARED_METHODS_CACHE.computeIfAbsent(beanClass,
key -> getMethodsDirectly(beanClass, false, Objects.equals(Object.class, beanClass)));
} }
/**
* 获得类中所有直接声明方法,不包括其父类中的方法
*
* @param clazz 类,非{@code null}
* @param predicate 方法过滤器,{@code null}表示无过滤
* @return 方法列表
* @throws SecurityException 安全检查异常
*/
public static Method[] getDeclaredMethods(final Class<?> clazz, final Predicate<Method> predicate) throws SecurityException {
return METHODS_CACHE.computeIfAbsent(Assert.notNull(clazz), MethodReflect::of).getDeclaredMethods(predicate);
}
// endregion
/** /**
* 获得一个类中所有方法列表,直接反射获取,无缓存<br> * 获得一个类中所有方法列表,直接反射获取,无缓存<br>
* 接口获取方法和默认方法,获取的方法包括: * 接口获取方法和默认方法,获取的方法包括:
@@ -371,27 +327,7 @@ public class MethodUtil {
* @throws SecurityException 安全检查异常 * @throws SecurityException 安全检查异常
*/ */
public static Method[] getMethodsDirectly(final Class<?> beanClass, final boolean withSupers, final boolean withMethodFromObject) throws SecurityException { public static Method[] getMethodsDirectly(final Class<?> beanClass, final boolean withSupers, final boolean withMethodFromObject) throws SecurityException {
Assert.notNull(beanClass); return MethodReflect.of(Assert.notNull(beanClass)).getMethodsDirectly(withSupers, withMethodFromObject);
if (beanClass.isInterface()) {
// 对于接口直接调用Class.getMethods方法获取所有方法因为接口都是public方法
return withSupers ? beanClass.getMethods() : beanClass.getDeclaredMethods();
}
final UniqueKeySet<String, Method> 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]);
} }
/** /**
@@ -562,7 +498,7 @@ public class MethodUtil {
return name.startsWith("get"); return name.startsWith("get");
} }
// --------------------------------------------------------------------------------------------------------- invoke // region ----- invoke
/** /**
* 执行静态方法 * 执行静态方法
@@ -760,6 +696,8 @@ public class MethodUtil {
} }
} }
// endregion
/** /**
* 检查用户传入参数: * 检查用户传入参数:
* <ul> * <ul>
@@ -804,46 +742,4 @@ public class MethodUtil {
return actualArgs; return actualArgs;
} }
/**
* 获取方法的唯一键,结构为:
* <pre>
* 返回类型#方法名:参数1类型,参数2类型...
* </pre>
*
* @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<Method> getDefaultMethodsFromInterface(final Class<?> clazz) {
final List<Method> result = new ArrayList<>();
for (final Class<?> ifc : clazz.getInterfaces()) {
for (final Method m : ifc.getMethods()) {
if (!ModifierUtil.isAbstract(m)) {
result.add(m);
}
}
}
return result;
}
} }

View File

@@ -180,14 +180,14 @@ public class MethodUtilTest {
@Test @Test
public void getPublicMethod() { 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); 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); 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); 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); Assertions.assertNull(privateMethod);
} }

View File

@@ -63,7 +63,7 @@ public class InvokeTask implements Task{
if(StrUtil.isBlank(methodName)) { if(StrUtil.isBlank(methodName)) {
throw new IllegalArgumentException("Method name is blank !"); throw new IllegalArgumentException("Method name is blank !");
} }
this.method = MethodUtil.getPublicMethod(clazz, methodName); this.method = MethodUtil.getPublicMethod(clazz, false, methodName);
if(null == this.method) { if(null == this.method) {
throw new IllegalArgumentException("No method with name of [" + methodName + "] !"); throw new IllegalArgumentException("No method with name of [" + methodName + "] !");
} }