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.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;
}
/**
* 获取指定类的所有父类结果不包括指定类本身<br>
* 如果无父类返回一个空的列表
@ -813,7 +782,7 @@ public class ClassUtil {
*/
public static void traverseTypeHierarchyWhile(
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();
}
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 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;
}
}

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;
}
final List<Method> 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]);

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.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}相关工具类包括方法获取和方法执行<br>
* TODO 与commons-beanutils相比Hutool缓存某个类的所有方法而commons缓存单个方法须性能测试哪个更加合理
*
* @author looly
*/
public class MethodUtil {
/**
* 方法缓存
*/
private static final WeakConcurrentMap<Class<?>, Method[]> METHODS_CACHE = new WeakConcurrentMap<>();
/**
* 直接声明的方法缓存
*/
private static final WeakConcurrentMap<Class<?>, Method[]> DECLARED_METHODS_CACHE = new WeakConcurrentMap<>();
private static final WeakConcurrentMap<Class<?>, MethodReflect> METHODS_CACHE = new WeakConcurrentMap<>();
// --------------------------------------------------------------------------------------------------------- method
// region ----- getMethods
/**
* 获得指定类本类及其父类中的Public方法名<br>
@ -60,85 +56,34 @@ public class MethodUtil {
* @return 方法名Set
*/
public static Set<String> getPublicMethodNames(final Class<?> clazz) {
final HashSet<String> 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方法列表<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()));
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<String> getMethodNames(final Class<?> clazz) throws SecurityException {
final HashSet<String> 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<Method> 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<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 方法列表
* @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<Method> predicate) throws SecurityException {
return METHODS_CACHE.computeIfAbsent(Assert.notNull(clazz), MethodReflect::of).getDeclaredMethods(predicate);
}
// endregion
/**
* 获得一个类中所有方法列表直接反射获取无缓存<br>
* 接口获取方法和默认方法获取的方法包括
@ -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<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]);
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> 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 <T> 对象类型
* @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 <T> 对象类型
* @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
/**
* 检查用户传入参数
* <ul>
@ -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;
}
/**
* 获取方法的唯一键结构为:
* <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
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);
}

View File

@ -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 + "] !");
}