mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-08-18 20:38:02 +08:00
add MethodReflect
This commit is contained in:
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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]);
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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 + "] !");
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user