add MethodUtil

This commit is contained in:
Looly 2022-05-05 00:24:08 +08:00
parent 140e1d546f
commit 6d7d350886
30 changed files with 1168 additions and 1234 deletions

View File

@ -1,6 +1,6 @@
package cn.hutool.core.annotation;
import cn.hutool.core.reflect.ReflectUtil;
import cn.hutool.core.reflect.MethodUtil;
import cn.hutool.core.text.StrUtil;
import java.io.Serializable;
@ -71,7 +71,7 @@ public class AnnotationProxy<T extends Annotation> implements Annotation, Invoca
* @return 属性方法结果映射
*/
private Map<String, Object> initAttributes() {
final Method[] methods = ReflectUtil.getMethods(this.type);
final Method[] methods = MethodUtil.getMethods(this.type);
final Map<String, Object> attributes = new HashMap<>(methods.length, 1);
for (final Method method : methods) {
@ -80,7 +80,7 @@ public class AnnotationProxy<T extends Annotation> implements Annotation, Invoca
continue;
}
attributes.put(method.getName(), ReflectUtil.invoke(this.annotation, method));
attributes.put(method.getName(), MethodUtil.invoke(this.annotation, method));
}
return attributes;

View File

@ -1,6 +1,7 @@
package cn.hutool.core.annotation;
import cn.hutool.core.exceptions.UtilException;
import cn.hutool.core.reflect.MethodUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.reflect.ReflectUtil;
@ -169,11 +170,11 @@ public class AnnotationUtil {
return null;
}
final Method method = ReflectUtil.getMethodOfObj(annotation, propertyName);
final Method method = MethodUtil.getMethodOfObj(annotation, propertyName);
if (null == method) {
return null;
}
return ReflectUtil.invoke(annotation, method);
return MethodUtil.invoke(annotation, method);
}
/**
@ -191,7 +192,7 @@ public class AnnotationUtil {
return null;
}
final Method[] methods = ReflectUtil.getMethods(annotationType, t -> {
final Method[] methods = MethodUtil.getMethods(annotationType, t -> {
if (ArrayUtil.isEmpty(t.getParameterTypes())) {
// 只读取无参方法
final String name = t.getName();
@ -205,7 +206,7 @@ public class AnnotationUtil {
final HashMap<String, Object> result = new HashMap<>(methods.length, 1);
for (final Method method : methods) {
result.put(method.getName(), ReflectUtil.invoke(annotation, method));
result.put(method.getName(), MethodUtil.invoke(annotation, method));
}
return result;
}

View File

@ -2,6 +2,7 @@ package cn.hutool.core.bean;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.map.CaseInsensitiveMap;
import cn.hutool.core.reflect.MethodUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.reflect.ModifierUtil;
import cn.hutool.core.reflect.ReflectUtil;
@ -140,7 +141,7 @@ public class BeanDesc implements Serializable {
* @return this
*/
private BeanDesc init() {
final Method[] gettersAndSetters = ReflectUtil.getMethods(this.beanClass, ReflectUtil::isGetterOrSetterIgnoreCase);
final Method[] gettersAndSetters = MethodUtil.getMethods(this.beanClass, MethodUtil::isGetterOrSetterIgnoreCase);
PropDesc prop;
for (final Field field : ReflectUtil.getFields(this.beanClass)) {
// 排除静态属性和对象子类

View File

@ -3,6 +3,7 @@ package cn.hutool.core.bean;
import cn.hutool.core.clone.CloneSupport;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.reflect.ClassUtil;
import cn.hutool.core.reflect.MethodUtil;
import cn.hutool.core.reflect.ReflectUtil;
import java.io.Serializable;
@ -169,7 +170,7 @@ public class DynaBean extends CloneSupport<DynaBean> implements Serializable {
* @return 执行结果可能为null
*/
public Object invoke(final String methodName, final Object... params) {
return ReflectUtil.invoke(this.bean, methodName, params);
return MethodUtil.invoke(this.bean, methodName, params);
}
/**

View File

@ -3,7 +3,7 @@ package cn.hutool.core.bean;
import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.annotation.PropIgnore;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.reflect.ClassUtil;
import cn.hutool.core.reflect.MethodUtil;
import cn.hutool.core.reflect.ModifierUtil;
import cn.hutool.core.reflect.ReflectUtil;
import cn.hutool.core.reflect.TypeUtil;
@ -43,8 +43,8 @@ public class PropDesc {
*/
public PropDesc(final Field field, final Method getter, final Method setter) {
this.field = field;
this.getter = ClassUtil.setAccessible(getter);
this.setter = ClassUtil.setAccessible(setter);
this.getter = ReflectUtil.setAccessible(getter);
this.setter = ReflectUtil.setAccessible(setter);
}
/**
@ -152,7 +152,7 @@ public class PropDesc {
*/
public Object getValue(final Object bean) {
if (null != this.getter) {
return ReflectUtil.invoke(bean, this.getter);
return MethodUtil.invoke(bean, this.getter);
} else if (ModifierUtil.isPublic(this.field)) {
return ReflectUtil.getFieldValue(bean, this.field);
}
@ -223,7 +223,7 @@ public class PropDesc {
*/
public PropDesc setValue(final Object bean, final Object value) {
if (null != this.setter) {
ReflectUtil.invoke(bean, this.setter, value);
MethodUtil.invoke(bean, this.setter, value);
} else if (ModifierUtil.isPublic(this.field)) {
ReflectUtil.setFieldValue(bean, this.field, value);
}

View File

@ -140,11 +140,12 @@ public class ClassLoaderUtil {
* 3内部类例如java.lang.Thread.State会被转为java.lang.Thread$State加载
* </pre>
*
* @param <T> 目标类的类型
* @param name 类名
* @return 类名对应的类
* @throws UtilException 包装{@link ClassNotFoundException}没有类名对应的类时抛出此异常
*/
public static Class<?> loadClass(final String name) throws UtilException {
public static <T> Class<T> loadClass(final String name) throws UtilException {
return loadClass(name, true);
}
@ -158,12 +159,13 @@ public class ClassLoaderUtil {
* 3内部类例如java.lang.Thread.State会被转为java.lang.Thread$State加载
* </pre>
*
* @param <T> 目标类的类型
* @param name 类名
* @param isInitialized 是否初始化类调用static模块内容和初始化static属性
* @return 类名对应的类
* @throws UtilException 包装{@link ClassNotFoundException}没有类名对应的类时抛出此异常
*/
public static Class<?> loadClass(final String name, final boolean isInitialized) throws UtilException {
public static <T> Class<T> loadClass(final String name, final boolean isInitialized) throws UtilException {
return loadClass(name, null, isInitialized);
}
@ -185,7 +187,8 @@ public class ClassLoaderUtil {
* @return 类名对应的类
* @throws UtilException 包装{@link ClassNotFoundException}没有类名对应的类时抛出此异常
*/
public static Class<?> loadClass(String name, ClassLoader classLoader, final boolean isInitialized) throws UtilException {
@SuppressWarnings("unchecked")
public static <T> Class<T> loadClass(String name, ClassLoader classLoader, final boolean isInitialized) throws UtilException {
Assert.notNull(name, "Name must not be null");
// 自动将包名中的"/"替换为"."
@ -201,7 +204,7 @@ public class ClassLoaderUtil {
final ClassLoader finalClassLoader = classLoader;
clazz = CLASS_CACHE.computeIfAbsent(Pair.of(name, classLoader), (key)-> doLoadClass(finalName, finalClassLoader, isInitialized));
}
return clazz;
return (Class<T>) clazz;
}
/**

View File

@ -3,7 +3,7 @@ package cn.hutool.core.classloader;
import cn.hutool.core.exceptions.UtilException;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.net.URLUtil;
import cn.hutool.core.reflect.ReflectUtil;
import cn.hutool.core.reflect.MethodUtil;
import java.io.File;
import java.io.IOException;
@ -53,12 +53,12 @@ public class JarClassLoader extends URLClassLoader {
*/
public static void loadJar(final URLClassLoader loader, final File jarFile) throws UtilException {
try {
final Method method = ReflectUtil.getMethod(URLClassLoader.class, "addURL", URL.class);
final Method method = MethodUtil.getMethod(URLClassLoader.class, "addURL", URL.class);
if (null != method) {
method.setAccessible(true);
final List<File> jars = loopJar(jarFile);
for (final File jar : jars) {
ReflectUtil.invoke(loader, method, jar.toURI().toURL());
MethodUtil.invoke(loader, method, jar.toURI().toURL());
}
}
} catch (final IOException e) {

View File

@ -1,7 +1,7 @@
package cn.hutool.core.clone;
import cn.hutool.core.reflect.ReflectUtil;
import cn.hutool.core.reflect.MethodUtil;
/**
* 克隆默认实现接口用于实现返回指定泛型类型的克隆方法
@ -18,7 +18,7 @@ public interface DefaultCloneable<T> extends java.lang.Cloneable {
*/
default T clone0() {
try {
return ReflectUtil.invoke(this, "clone");
return MethodUtil.invoke(this, "clone");
} catch (final Exception e) {
throw new CloneRuntimeException(e);
}

View File

@ -8,6 +8,7 @@ import cn.hutool.core.lang.func.Filter;
import cn.hutool.core.lang.func.Matcher;
import cn.hutool.core.lang.func.Func1;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.reflect.MethodUtil;
import cn.hutool.core.text.StrJoiner;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjUtil;
@ -1046,7 +1047,7 @@ public class IterUtil {
// 反射获取
try {
final Object iterator = ReflectUtil.invoke(obj, "iterator");
final Object iterator = MethodUtil.invoke(obj, "iterator");
if (iterator instanceof Iterator) {
return (Iterator<?>) iterator;
}

View File

@ -1,17 +1,17 @@
package cn.hutool.core.convert;
import cn.hutool.core.classloader.ClassLoaderUtil;
import cn.hutool.core.codec.HexUtil;
import cn.hutool.core.convert.impl.CollectionConverter;
import cn.hutool.core.convert.impl.EnumConverter;
import cn.hutool.core.convert.impl.MapConverter;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.reflect.TypeReference;
import cn.hutool.core.text.StrUtil;
import cn.hutool.core.text.UnicodeUtil;
import cn.hutool.core.util.ByteUtil;
import cn.hutool.core.util.CharUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.reflect.ClassUtil;
import cn.hutool.core.codec.HexUtil;
import cn.hutool.core.text.StrUtil;
import java.lang.reflect.Type;
import java.math.BigDecimal;
@ -627,7 +627,7 @@ public class Convert {
* @throws ConvertException 转换器不存在
*/
public static <T> T convertByClassName(final String className, final Object value) throws ConvertException{
return convert(ClassUtil.loadClass(className), value);
return convert(ClassLoaderUtil.loadClass(className), value);
}
/**

View File

@ -6,9 +6,9 @@ import cn.hutool.core.lang.EnumItem;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.map.WeakConcurrentMap;
import cn.hutool.core.reflect.ClassUtil;
import cn.hutool.core.util.EnumUtil;
import cn.hutool.core.reflect.MethodUtil;
import cn.hutool.core.reflect.ModifierUtil;
import cn.hutool.core.reflect.ReflectUtil;
import cn.hutool.core.util.EnumUtil;
import java.lang.reflect.Method;
import java.util.Arrays;
@ -96,7 +96,7 @@ public class EnumConverter extends AbstractConverter<Object> {
final Class<?> valueClass = value.getClass();
for (final Map.Entry<Class<?>, Method> entry : methodMap.entrySet()) {
if (ClassUtil.isAssignable(entry.getKey(), valueClass)) {
return ReflectUtil.invokeStatic(entry.getValue(), value);
return MethodUtil.invokeStatic(entry.getValue(), value);
}
}
}

View File

@ -1,8 +1,8 @@
package cn.hutool.core.io.resource;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.classloader.ClassLoaderUtil;
import cn.hutool.core.reflect.ReflectUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.reflect.MethodUtil;
import java.io.InputStream;
import java.lang.reflect.Method;
@ -63,22 +63,22 @@ public class VfsResource implements Resource {
* @return 文件是否存在
*/
public boolean exists() {
return ReflectUtil.invoke(virtualFile, VIRTUAL_FILE_METHOD_EXISTS);
return MethodUtil.invoke(virtualFile, VIRTUAL_FILE_METHOD_EXISTS);
}
@Override
public String getName() {
return ReflectUtil.invoke(virtualFile, VIRTUAL_FILE_METHOD_GET_NAME);
return MethodUtil.invoke(virtualFile, VIRTUAL_FILE_METHOD_GET_NAME);
}
@Override
public URL getUrl() {
return ReflectUtil.invoke(virtualFile, VIRTUAL_FILE_METHOD_TO_URL);
return MethodUtil.invoke(virtualFile, VIRTUAL_FILE_METHOD_TO_URL);
}
@Override
public InputStream getStream() {
return ReflectUtil.invoke(virtualFile, VIRTUAL_FILE_METHOD_GET_INPUT_STREAM);
return MethodUtil.invoke(virtualFile, VIRTUAL_FILE_METHOD_GET_INPUT_STREAM);
}
@Override
@ -92,7 +92,7 @@ public class VfsResource implements Resource {
* @return 最后修改时间
*/
public long getLastModified() {
return ReflectUtil.invoke(virtualFile, VIRTUAL_FILE_METHOD_GET_LAST_MODIFIED);
return MethodUtil.invoke(virtualFile, VIRTUAL_FILE_METHOD_GET_LAST_MODIFIED);
}
/**
@ -101,7 +101,7 @@ public class VfsResource implements Resource {
* @return VFS文件大小
*/
public long size() {
return ReflectUtil.invoke(virtualFile, VIRTUAL_FILE_METHOD_GET_SIZE);
return MethodUtil.invoke(virtualFile, VIRTUAL_FILE_METHOD_GET_SIZE);
}
}

View File

@ -1,10 +1,10 @@
package cn.hutool.core.lang;
import cn.hutool.core.classloader.ClassLoaderUtil;
import cn.hutool.core.lang.func.Func0;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.reflect.ClassUtil;
import cn.hutool.core.reflect.ReflectUtil;
import cn.hutool.core.text.StrUtil;
import cn.hutool.core.util.ArrayUtil;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
@ -66,7 +66,7 @@ public final class Singleton {
*/
public static <T> T get(final String className, final Object... params) {
Assert.notBlank(className, "Class name must be not blank !");
final Class<T> clazz = ClassUtil.loadClass(className);
final Class<T> clazz = ClassLoaderUtil.loadClass(className);
return get(clazz, params);
}

View File

@ -1,9 +1,9 @@
package cn.hutool.core.lang.func;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.classloader.ClassLoaderUtil;
import cn.hutool.core.map.WeakConcurrentMap;
import cn.hutool.core.reflect.ClassUtil;
import cn.hutool.core.reflect.ReflectUtil;
import cn.hutool.core.reflect.MethodUtil;
import cn.hutool.core.text.StrUtil;
import java.io.Serializable;
@ -57,7 +57,7 @@ public class LambdaUtil {
public static <R> Class<R> getRealClass(final Func0<?> func) {
final SerializedLambda lambda = resolve(func);
checkLambdaTypeCanGetClass(lambda.getImplMethodKind());
return ClassUtil.loadClass(lambda.getImplClass());
return ClassLoaderUtil.loadClass(lambda.getImplClass());
}
/**
@ -134,7 +134,7 @@ public class LambdaUtil {
final SerializedLambda lambda = resolve(func);
checkLambdaTypeCanGetClass(lambda.getImplMethodKind());
final String instantiatedMethodType = lambda.getInstantiatedMethodType();
return ClassUtil.loadClass(StrUtil.sub(instantiatedMethodType, 2, StrUtil.indexOf(instantiatedMethodType, ';')));
return ClassLoaderUtil.loadClass(StrUtil.sub(instantiatedMethodType, 2, StrUtil.indexOf(instantiatedMethodType, ';')));
}
/**
@ -202,7 +202,7 @@ public class LambdaUtil {
* @return 返回解析后的结果
*/
private static SerializedLambda _resolve(final Serializable func) {
return cache.computeIfAbsent(func.getClass().getName(), (key) -> ReflectUtil.invoke(func, "writeReplace"));
return cache.computeIfAbsent(func.getClass().getName(), (key) -> MethodUtil.invoke(func, "writeReplace"));
}
//endregion
}

View File

@ -6,9 +6,7 @@ import cn.hutool.core.convert.BasicType;
import cn.hutool.core.exceptions.UtilException;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.ClassScanner;
import cn.hutool.core.lang.Singleton;
import cn.hutool.core.net.URLDecoder;
import cn.hutool.core.net.URLUtil;
import cn.hutool.core.text.StrUtil;
@ -18,7 +16,6 @@ import cn.hutool.core.util.CharsetUtil;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.net.URI;
@ -358,124 +355,6 @@ public class ClassUtil {
return true;
}
/**
* 加载类
*
* @param <T> 对象类型
* @param className 类名
* @param isInitialized 是否初始化
* @return
*/
@SuppressWarnings("unchecked")
public static <T> Class<T> loadClass(final String className, final boolean isInitialized) {
return (Class<T>) ClassLoaderUtil.loadClass(className, isInitialized);
}
/**
* 加载类并初始化
*
* @param <T> 对象类型
* @param className 类名
* @return
*/
public static <T> Class<T> loadClass(final String className) {
return loadClass(className, true);
}
// ---------------------------------------------------------------------------------------------------- Invoke start
/**
* 执行方法<br>
* 可执行Private方法也可执行static方法<br>
* 执行非static方法时必须满足对象有默认构造方法<br>
* 非单例模式如果是非静态方法每次创建一个新对象
*
* @param <T> 对象类型
* @param classNameWithMethodName 类名和方法名表达式类名与方法名用{@code .}{@code #}连接 例如com.xiaoleilu.hutool.StrUtil.isEmpty com.xiaoleilu.hutool.StrUtil#isEmpty
* @param args 参数必须严格对应指定方法的参数类型和数量
* @return 返回结果
*/
public static <T> T invoke(final String classNameWithMethodName, final Object[] args) {
return invoke(classNameWithMethodName, false, args);
}
/**
* 执行方法<br>
* 可执行Private方法也可执行static方法<br>
* 执行非static方法时必须满足对象有默认构造方法<br>
*
* @param <T> 对象类型
* @param classNameWithMethodName 类名和方法名表达式例如com.xiaoleilu.hutool.StrUtil#isEmpty或com.xiaoleilu.hutool.StrUtil.isEmpty
* @param isSingleton 是否为单例对象如果此参数为false每次执行方法时创建一个新对象
* @param args 参数必须严格对应指定方法的参数类型和数量
* @return 返回结果
*/
public static <T> T invoke(final String classNameWithMethodName, final boolean isSingleton, final Object... args) {
if (StrUtil.isBlank(classNameWithMethodName)) {
throw new UtilException("Blank classNameDotMethodName!");
}
int splitIndex = classNameWithMethodName.lastIndexOf('#');
if (splitIndex <= 0) {
splitIndex = classNameWithMethodName.lastIndexOf('.');
}
if (splitIndex <= 0) {
throw new UtilException("Invalid classNameWithMethodName [{}]!", classNameWithMethodName);
}
final String className = classNameWithMethodName.substring(0, splitIndex);
final String methodName = classNameWithMethodName.substring(splitIndex + 1);
return invoke(className, methodName, isSingleton, args);
}
/**
* 执行方法<br>
* 可执行Private方法也可执行static方法<br>
* 执行非static方法时必须满足对象有默认构造方法<br>
* 非单例模式如果是非静态方法每次创建一个新对象
*
* @param <T> 对象类型
* @param className 类名完整类路径
* @param methodName 方法名
* @param args 参数必须严格对应指定方法的参数类型和数量
* @return 返回结果
*/
public static <T> T invoke(final String className, final String methodName, final Object[] args) {
return invoke(className, methodName, false, args);
}
/**
* 执行方法<br>
* 可执行Private方法也可执行static方法<br>
* 执行非static方法时必须满足对象有默认构造方法<br>
*
* @param <T> 对象类型
* @param className 类名完整类路径
* @param methodName 方法名
* @param isSingleton 是否为单例对象如果此参数为false每次执行方法时创建一个新对象
* @param args 参数必须严格对应指定方法的参数类型和数量
* @return 返回结果
*/
public static <T> T invoke(final String className, final String methodName, final boolean isSingleton, final Object... args) {
final Class<Object> clazz = loadClass(className);
try {
final Method method = ReflectUtil.getMethod(clazz, methodName, getClasses(args));
if (null == method) {
throw new NoSuchMethodException(StrUtil.format("No such method: [{}]", methodName));
}
if (isStatic(method)) {
return ReflectUtil.invoke(null, method, args);
} else {
return ReflectUtil.invoke(isSingleton ? Singleton.get(clazz) : clazz.newInstance(), method, args);
}
} catch (final Exception e) {
throw new UtilException(e);
}
}
// ---------------------------------------------------------------------------------------------------- Invoke end
/**
* 是否为包装类型
*
@ -580,74 +459,6 @@ public class ClassUtil {
}
}
/**
* 指定类是否为Public
*
* @param clazz
* @return 是否为public
*/
public static boolean isPublic(final Class<?> clazz) {
if (null == clazz) {
throw new NullPointerException("Class to provided is null.");
}
return Modifier.isPublic(clazz.getModifiers());
}
/**
* 指定方法是否为Public
*
* @param method 方法
* @return 是否为public
*/
public static boolean isPublic(final Method method) {
Assert.notNull(method, "Method to provided is null.");
return Modifier.isPublic(method.getModifiers());
}
/**
* 指定类是否为非public
*
* @param clazz
* @return 是否为非public
*/
public static boolean isNotPublic(final Class<?> clazz) {
return false == isPublic(clazz);
}
/**
* 指定方法是否为非public
*
* @param method 方法
* @return 是否为非public
*/
public static boolean isNotPublic(final Method method) {
return false == isPublic(method);
}
/**
* 是否为静态方法
*
* @param method 方法
* @return 是否为静态方法
*/
public static boolean isStatic(final Method method) {
Assert.notNull(method, "Method to provided is null.");
return Modifier.isStatic(method.getModifiers());
}
/**
* 设置方法为可访问
*
* @param method 方法
* @return 方法
*/
public static Method setAccessible(final Method method) {
if (null != method && false == method.isAccessible()) {
method.setAccessible(true);
}
return method;
}
/**
* 是否为抽象类
*

View File

@ -14,7 +14,7 @@ import java.lang.reflect.Method;
* 方法句柄是一个有类型的可以直接执行的指向底层方法构造器field等的引用可以简单理解为函数指针它是一种更加底层的查找调整和调用方法的机制
* 参考
* <ul>
* <li>https://stackoverflow.com/questions/22614746/how-do-i-invoke-java-8-default-methods-reflectively</li>
* <li><a href="https://stackoverflow.com/questions/22614746/how-do-i-invoke-java-8-default-methods-reflectively">https://stackoverflow.com/questions/22614746/how-do-i-invoke-java-8-default-methods-reflectively</a></li>
* </ul>
*
* @author looly
@ -138,7 +138,7 @@ public class MethodHandleUtil {
Assert.notNull(obj, "Object to get method must be not null!");
Assert.notBlank(methodName, "Method name must be not blank!");
final Method method = ReflectUtil.getMethodOfObj(obj, methodName, args);
final Method method = MethodUtil.getMethodOfObj(obj, methodName, args);
if (null == method) {
throw new UtilException("No such method: [{}] from [{}]", methodName, obj.getClass());
}

View File

@ -0,0 +1,734 @@
package cn.hutool.core.reflect;
import cn.hutool.core.bean.NullWrapperBean;
import cn.hutool.core.classloader.ClassLoaderUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.UniqueKeySet;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.exceptions.UtilException;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Singleton;
import cn.hutool.core.lang.func.Filter;
import cn.hutool.core.map.WeakConcurrentMap;
import cn.hutool.core.text.StrUtil;
import cn.hutool.core.util.ArrayUtil;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class MethodUtil {
/**
* 方法缓存
*/
private static final WeakConcurrentMap<Class<?>, Method[]> METHODS_CACHE = new WeakConcurrentMap<>();
// --------------------------------------------------------------------------------------------------------- method
/**
* 获得指定类本类及其父类中的Public方法名<br>
* 去重重载的方法
*
* @param clazz
* @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 filter 过滤器
* @return 过滤后的方法数组
*/
public static Method[] getPublicMethods(final Class<?> clazz, final Filter<Method> filter) {
if (null == clazz) {
return null;
}
final Method[] methods = getPublicMethods(clazz);
if(null == filter){
return methods;
}
return ArrayUtil.filter(methods, filter);
}
/**
* 获得指定类过滤后的Public方法列表
*
* @param clazz 查找方法的类
* @param excludeMethods 不包括的方法
* @return 过滤后的方法列表
*/
public static Method[] getPublicMethods(final Class<?> clazz, final Method... excludeMethods) {
final HashSet<Method> excludeMethodSet = CollUtil.newHashSet(excludeMethods);
return getPublicMethods(clazz, method -> false == excludeMethodSet.contains(method));
}
/**
* 获得指定类过滤后的Public方法列表
*
* @param clazz 查找方法的类
* @param excludeMethodNames 不包括的方法名列表
* @return 过滤后的方法数组
*/
public static Method[] getPublicMethods(final Class<?> clazz, final String... excludeMethodNames) {
final HashSet<String> excludeMethodNameSet = CollUtil.newHashSet(excludeMethodNames);
return getPublicMethods(clazz, method -> false == excludeMethodNameSet.contains(method.getName()));
}
/**
* 查找指定Public方法 如果找不到对应的方法或方法不为public的则返回{@code null}
*
* @param clazz
* @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) {
return null;
}
}
/**
* 查找指定对象中的所有方法包括非public方法也包括父对象和Object类的方法
*
* <p>
* 此方法为精准获取方法名即方法名和参数数量和类型必须一致否则返回{@code null}
* </p>
*
* @param obj 被查找的对象如果为{@code null}返回{@code null}
* @param methodName 方法名如果为空字符串返回{@code null}
* @param args 参数
* @return 方法
* @throws SecurityException 无访问权限抛出异常
*/
public static Method getMethodOfObj(final Object obj, final String methodName, final Object... args) throws SecurityException {
if (null == obj || StrUtil.isBlank(methodName)) {
return null;
}
return getMethod(obj.getClass(), methodName, ClassUtil.getClasses(args));
}
/**
* 忽略大小写查找指定方法如果找不到对应的方法则返回{@code null}
*
* <p>
* 此方法为精准获取方法名即方法名和参数数量和类型必须一致否则返回{@code null}
* </p>
*
* @param clazz 如果为{@code null}返回{@code null}
* @param methodName 方法名如果为空字符串返回{@code null}
* @param paramTypes 参数类型指定参数类型如果是方法的子类也算
* @return 方法
* @throws SecurityException 无权访问抛出异常
* @since 3.2.0
*/
public static Method getMethodIgnoreCase(final Class<?> clazz, final String methodName, final Class<?>... paramTypes) throws SecurityException {
return getMethod(clazz, true, methodName, paramTypes);
}
/**
* 查找指定方法 如果找不到对应的方法则返回{@code null}
*
* <p>
* 此方法为精准获取方法名即方法名和参数数量和类型必须一致否则返回{@code null}
* </p>
*
* @param clazz 如果为{@code null}返回{@code null}
* @param methodName 方法名如果为空字符串返回{@code null}
* @param paramTypes 参数类型指定参数类型如果是方法的子类也算
* @return 方法
* @throws SecurityException 无权访问抛出异常
*/
public static Method getMethod(final Class<?> clazz, final String methodName, final Class<?>... paramTypes) throws SecurityException {
return getMethod(clazz, false, methodName, paramTypes);
}
/**
* 查找指定方法 如果找不到对应的方法则返回{@code null}<br>
* 此方法为精准获取方法名即方法名和参数数量和类型必须一致否则返回{@code null}<br>
* 如果查找的方法有多个同参数类型重载查找第一个找到的方法
*
* @param clazz 如果为{@code null}返回{@code null}
* @param ignoreCase 是否忽略大小写
* @param methodName 方法名如果为空字符串返回{@code null}
* @param paramTypes 参数类型指定参数类型如果是方法的子类也算
* @return 方法
* @throws SecurityException 无权访问抛出异常
* @since 3.2.0
*/
public static Method getMethod(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 = 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
&& false == method.isBridge()) {
return method;
}
}
}
return null;
}
/**
* 按照方法名查找指定方法名的方法只返回匹配到的第一个方法如果找不到对应的方法则返回{@code null}
*
* <p>
* 此方法只检查方法名是否一致并不检查参数的一致性
* </p>
*
* @param clazz 如果为{@code null}返回{@code null}
* @param methodName 方法名如果为空字符串返回{@code null}
* @return 方法
* @throws SecurityException 无权访问抛出异常
* @since 4.3.2
*/
public static Method getMethodByName(final Class<?> clazz, final String methodName) throws SecurityException {
return getMethodByName(clazz, false, methodName);
}
/**
* 按照方法名查找指定方法名的方法只返回匹配到的第一个方法如果找不到对应的方法则返回{@code null}
*
* <p>
* 此方法只检查方法名是否一致忽略大小写并不检查参数的一致性
* </p>
*
* @param clazz 如果为{@code null}返回{@code null}
* @param methodName 方法名如果为空字符串返回{@code null}
* @return 方法
* @throws SecurityException 无权访问抛出异常
* @since 4.3.2
*/
public static Method getMethodByNameIgnoreCase(final Class<?> clazz, final String methodName) throws SecurityException {
return getMethodByName(clazz, true, methodName);
}
/**
* 按照方法名查找指定方法名的方法只返回匹配到的第一个方法如果找不到对应的方法则返回{@code null}
*
* <p>
* 此方法只检查方法名是否一致并不检查参数的一致性
* </p>
*
* @param clazz 如果为{@code null}返回{@code null}
* @param ignoreCase 是否忽略大小写
* @param methodName 方法名如果为空字符串返回{@code null}
* @return 方法
* @throws SecurityException 无权访问抛出异常
* @since 4.3.2
*/
public static Method getMethodByName(final Class<?> clazz, final boolean ignoreCase, final String methodName) throws SecurityException {
if (null == clazz || StrUtil.isBlank(methodName)) {
return null;
}
final Method[] methods = getMethods(clazz);
if (ArrayUtil.isNotEmpty(methods)) {
for (final Method method : methods) {
if (StrUtil.equals(methodName, method.getName(), ignoreCase)
// 排除桥接方法
&& false == method.isBridge()) {
return method;
}
}
}
return null;
}
/**
* 获得指定类中的Public方法名<br>
* 去重重载的方法
*
* @param clazz
* @return 方法名Set
* @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;
}
/**
* 获得指定类过滤后的Public方法列表
*
* @param clazz 查找方法的类
* @param filter 过滤器
* @return 过滤后的方法列表
* @throws SecurityException 安全异常
*/
public static Method[] getMethods(final Class<?> clazz, final Filter<Method> filter) throws SecurityException {
if (null == clazz) {
return null;
}
return ArrayUtil.filter(getMethods(clazz), filter);
}
/**
* 获得一个类中所有方法列表包括其父类中的方法
*
* @param beanClass {@code null}
* @return 方法列表
* @throws SecurityException 安全检查异常
*/
public static Method[] getMethods(final Class<?> beanClass) throws SecurityException {
Assert.notNull(beanClass);
return METHODS_CACHE.computeIfAbsent(beanClass,
() -> getMethodsDirectly(beanClass, true, true));
}
/**
* 获得一个类中所有方法列表直接反射获取无缓存<br>
* 接口获取方法和默认方法获取的方法包括
* <ul>
* <li>本类中的所有方法包括static方法</li>
* <li>父类中的所有方法包括static方法</li>
* <li>Object中包括static方法</li>
* </ul>
*
* @param beanClass 类或接口
* @param withSupers 是否包括父类或接口的方法列表
* @param withMethodFromObject 是否包括Object中的方法
* @return 方法列表
* @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 (false == withMethodFromObject && Object.class == searchType) {
break;
}
result.addAllIfAbsent(Arrays.asList(searchType.getDeclaredMethods()));
result.addAllIfAbsent(getDefaultMethodsFromInterface(searchType));
searchType = (withSupers && false == searchType.isInterface()) ? searchType.getSuperclass() : null;
}
return result.toArray(new Method[0]);
}
/**
* 是否为equals方法
*
* @param method 方法
* @return 是否为equals方法
*/
public static boolean isEqualsMethod(final Method method) {
if (method == null ||
1 != method.getParameterCount() ||
false == "equals".equals(method.getName())) {
return false;
}
return (method.getParameterTypes()[0] == Object.class);
}
/**
* 是否为hashCode方法
*
* @param method 方法
* @return 是否为hashCode方法
*/
public static boolean isHashCodeMethod(final Method method) {
return method != null//
&& "hashCode".equals(method.getName())//
&& isEmptyParam(method);
}
/**
* 是否为toString方法
*
* @param method 方法
* @return 是否为toString方法
*/
public static boolean isToStringMethod(final Method method) {
return method != null//
&& "toString".equals(method.getName())//
&& isEmptyParam(method);
}
/**
* 是否为无参数方法
*
* @param method 方法
* @return 是否为无参数方法
* @since 5.1.1
*/
public static boolean isEmptyParam(final Method method) {
return method.getParameterCount() == 0;
}
/**
* 检查给定方法是否为Getter或者Setter方法规则为<br>
* <ul>
* <li>方法参数必须为0个或1个</li>
* <li>如果是无参方法则判断是否以getis开头</li>
* <li>如果方法参数1个则判断是否以set开头</li>
* </ul>
*
* @param method 方法
* @return 是否为Getter或者Setter方法
* @since 5.7.20
*/
public static boolean isGetterOrSetterIgnoreCase(final Method method) {
return isGetterOrSetter(method, true);
}
/**
* 检查给定方法是否为Getter或者Setter方法规则为<br>
* <ul>
* <li>方法参数必须为0个或1个</li>
* <li>方法名称不能是getClass</li>
* <li>如果是无参方法则判断是否以getis开头</li>
* <li>如果方法参数1个则判断是否以set开头</li>
* </ul>
*
* @param method 方法
* @param ignoreCase 是否忽略方法名的大小写
* @return 是否为Getter或者Setter方法
* @since 5.7.20
*/
public static boolean isGetterOrSetter(final Method method, final boolean ignoreCase) {
if (null == method) {
return false;
}
// 参数个数必须为0或1
final int parameterCount = method.getParameterCount();
if (parameterCount > 1) {
return false;
}
String name = method.getName();
// 跳过getClass这个特殊方法
if ("getClass".equals(name)) {
return false;
}
if (ignoreCase) {
name = name.toLowerCase();
}
switch (parameterCount) {
case 0:
return name.startsWith("get") || name.startsWith("is");
case 1:
return name.startsWith("set");
default:
return false;
}
}
// --------------------------------------------------------------------------------------------------------- invoke
/**
* 执行静态方法
*
* @param <T> 对象类型
* @param method 方法对象方法或static方法都可
* @param args 参数对象
* @return 结果
* @throws UtilException 多种异常包装
*/
public static <T> T invokeStatic(final Method method, final Object... args) throws UtilException {
return invoke(null, method, args);
}
/**
* 执行方法<br>
* 执行前要检查给定参数
*
* <pre>
* 1. 参数个数是否与方法参数个数一致
* 2. 如果某个参数为null但是方法这个位置的参数为原始类型则赋予原始类型默认值
* </pre>
*
* @param <T> 返回对象类型
* @param obj 对象如果执行静态方法此值为{@code null}
* @param method 方法对象方法或static方法都可
* @param args 参数对象
* @return 结果
* @throws UtilException 一些列异常的包装
*/
public static <T> T invokeWithCheck(final Object obj, final Method method, final Object... args) throws UtilException {
final Class<?>[] types = method.getParameterTypes();
if (null != args) {
Assert.isTrue(args.length == types.length, "Params length [{}] is not fit for param length [{}] of method !", args.length, types.length);
Class<?> type;
for (int i = 0; i < args.length; i++) {
type = types[i];
if (type.isPrimitive() && null == args[i]) {
// 参数是原始类型而传入参数为null时赋予默认值
args[i] = ClassUtil.getDefaultValue(type);
}
}
}
return invoke(obj, method, args);
}
/**
* 执行方法
*
* <p>
* 对于用户传入参数会做必要检查包括
*
* <pre>
* 1忽略多余的参数
* 2参数不够补齐默认值
* 3传入参数为null但是目标参数类型为原始类型做转换
* </pre>
*
* @param <T> 返回对象类型
* @param obj 对象如果执行静态方法此值为{@code null}
* @param method 方法对象方法或static方法都可
* @param args 参数对象
* @return 结果
* @throws UtilException 一些列异常的包装
*/
@SuppressWarnings("unchecked")
public static <T> T invoke(final Object obj, final Method method, final Object... args) throws UtilException {
ReflectUtil.setAccessible(method);
// 检查用户传入参数
// 1忽略多余的参数
// 2参数不够补齐默认值
// 3通过NullWrapperBean传递的参数,会直接赋值null
// 4传入参数为null但是目标参数类型为原始类型做转换
// 5传入参数类型不对应尝试转换类型
final Class<?>[] parameterTypes = method.getParameterTypes();
final Object[] actualArgs = new Object[parameterTypes.length];
if (null != args) {
for (int i = 0; i < actualArgs.length; i++) {
if (i >= args.length || null == args[i]) {
// 越界或者空值
actualArgs[i] = ClassUtil.getDefaultValue(parameterTypes[i]);
} else if (args[i] instanceof NullWrapperBean) {
//如果是通过NullWrapperBean传递的null参数,直接赋值null
actualArgs[i] = null;
} else if (false == parameterTypes[i].isAssignableFrom(args[i].getClass())) {
//对于类型不同的字段尝试转换转换失败则使用原对象类型
final Object targetValue = Convert.convert(parameterTypes[i], args[i]);
if (null != targetValue) {
actualArgs[i] = targetValue;
}
} else {
actualArgs[i] = args[i];
}
}
}
if (method.isDefault()) {
// 当方法是default方法时尤其对象是代理对象需使用句柄方式执行
// 代理对象情况下调用method.invoke会导致循环引用执行最终栈溢出
return MethodHandleUtil.invokeSpecial(obj, method, args);
}
try {
return (T) method.invoke(ModifierUtil.isStatic(method) ? null : obj, actualArgs);
} catch (final Exception e) {
throw new UtilException(e);
}
}
/**
* 执行对象中指定方法
* 如果需要传递的参数为null,请使用NullWrapperBean来传递,不然会丢失类型信息
*
* @param <T> 返回对象类型
* @param obj 方法所在对象
* @param methodName 方法名
* @param args 参数列表
* @return 执行结果
* @throws UtilException IllegalAccessException包装
* @see NullWrapperBean
* @since 3.1.2
*/
public static <T> T invoke(final Object obj, final String methodName, final Object... args) throws UtilException {
Assert.notNull(obj, "Object to get method must be not null!");
Assert.notBlank(methodName, "Method name must be not blank!");
final Method method = getMethodOfObj(obj, methodName, args);
if (null == method) {
throw new UtilException("No such method: [{}] from [{}]", methodName, obj.getClass());
}
return invoke(obj, method, args);
}
/**
* 执行方法<br>
* 可执行Private方法也可执行static方法<br>
* 执行非static方法时必须满足对象有默认构造方法<br>
* 非单例模式如果是非静态方法每次创建一个新对象
*
* @param <T> 对象类型
* @param classNameWithMethodName 类名和方法名表达式类名与方法名用{@code .}{@code #}连接 例如com.xiaoleilu.hutool.StrUtil.isEmpty com.xiaoleilu.hutool.StrUtil#isEmpty
* @param args 参数必须严格对应指定方法的参数类型和数量
* @return 返回结果
*/
public static <T> T invoke(final String classNameWithMethodName, final Object[] args) {
return invoke(classNameWithMethodName, false, args);
}
/**
* 执行方法<br>
* 可执行Private方法也可执行static方法<br>
* 执行非static方法时必须满足对象有默认构造方法<br>
*
* @param <T> 对象类型
* @param classNameWithMethodName 类名和方法名表达式例如com.xiaoleilu.hutool.StrUtil#isEmpty或com.xiaoleilu.hutool.StrUtil.isEmpty
* @param isSingleton 是否为单例对象如果此参数为false每次执行方法时创建一个新对象
* @param args 参数必须严格对应指定方法的参数类型和数量
* @return 返回结果
*/
public static <T> T invoke(final String classNameWithMethodName, final boolean isSingleton, final Object... args) {
if (StrUtil.isBlank(classNameWithMethodName)) {
throw new UtilException("Blank classNameDotMethodName!");
}
int splitIndex = classNameWithMethodName.lastIndexOf('#');
if (splitIndex <= 0) {
splitIndex = classNameWithMethodName.lastIndexOf('.');
}
if (splitIndex <= 0) {
throw new UtilException("Invalid classNameWithMethodName [{}]!", classNameWithMethodName);
}
final String className = classNameWithMethodName.substring(0, splitIndex);
final String methodName = classNameWithMethodName.substring(splitIndex + 1);
return invoke(className, methodName, isSingleton, args);
}
/**
* 执行方法<br>
* 可执行Private方法也可执行static方法<br>
* 执行非static方法时必须满足对象有默认构造方法<br>
* 非单例模式如果是非静态方法每次创建一个新对象
*
* @param <T> 对象类型
* @param className 类名完整类路径
* @param methodName 方法名
* @param args 参数必须严格对应指定方法的参数类型和数量
* @return 返回结果
*/
public static <T> T invoke(final String className, final String methodName, final Object[] args) {
return invoke(className, methodName, false, args);
}
/**
* 执行方法<br>
* 可执行Private方法也可执行static方法<br>
* 执行非static方法时必须满足对象有默认构造方法<br>
*
* @param <T> 对象类型
* @param className 类名完整类路径
* @param methodName 方法名
* @param isSingleton 是否为单例对象如果此参数为false每次执行方法时创建一个新对象
* @param args 参数必须严格对应指定方法的参数类型和数量
* @return 返回结果
*/
public static <T> T invoke(final String className, final String methodName, final boolean isSingleton, final Object... args) {
final Class<?> clazz = ClassLoaderUtil.loadClass(className);
try {
final Method method = MethodUtil.getMethod(clazz, methodName, ClassUtil.getClasses(args));
if (null == method) {
throw new NoSuchMethodException(StrUtil.format("No such method: [{}]", methodName));
}
if (ModifierUtil.isStatic(method)) {
return MethodUtil.invoke(null, method, args);
} else {
return MethodUtil.invoke(isSingleton ? Singleton.get(clazz) : clazz.newInstance(), method, args);
}
} catch (final Exception e) {
throw new UtilException(e);
}
}
/**
* 获取方法的唯一键结构为:
* <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 (false == ModifierUtil.isAbstract(m)) {
result.add(m);
}
}
}
return result;
}
}

View File

@ -1,9 +1,6 @@
package cn.hutool.core.reflect;
import cn.hutool.core.annotation.Alias;
import cn.hutool.core.bean.NullWrapperBean;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.UniqueKeySet;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.exceptions.UtilException;
import cn.hutool.core.lang.Assert;
@ -17,10 +14,8 @@ import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@ -43,11 +38,6 @@ public class ReflectUtil {
* 字段缓存
*/
private static final WeakConcurrentMap<Class<?>, Field[]> FIELDS_CACHE = new WeakConcurrentMap<>();
/**
* 方法缓存
*/
private static final WeakConcurrentMap<Class<?>, Method[]> METHODS_CACHE = new WeakConcurrentMap<>();
// --------------------------------------------------------------------------------------------------------- Constructor
/**
@ -374,442 +364,6 @@ public class ReflectUtil {
return "this$0".equals(field.getName());
}
// --------------------------------------------------------------------------------------------------------- method
/**
* 获得指定类本类及其父类中的Public方法名<br>
* 去重重载的方法
*
* @param clazz
* @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 filter 过滤器
* @return 过滤后的方法数组
*/
public static Method[] getPublicMethods(final Class<?> clazz, final Filter<Method> filter) {
if (null == clazz) {
return null;
}
final Method[] methods = getPublicMethods(clazz);
if(null == filter){
return methods;
}
return ArrayUtil.filter(methods, filter);
}
/**
* 获得指定类过滤后的Public方法列表
*
* @param clazz 查找方法的类
* @param excludeMethods 不包括的方法
* @return 过滤后的方法列表
*/
public static Method[] getPublicMethods(final Class<?> clazz, final Method... excludeMethods) {
final HashSet<Method> excludeMethodSet = CollUtil.newHashSet(excludeMethods);
return getPublicMethods(clazz, method -> false == excludeMethodSet.contains(method));
}
/**
* 获得指定类过滤后的Public方法列表
*
* @param clazz 查找方法的类
* @param excludeMethodNames 不包括的方法名列表
* @return 过滤后的方法数组
*/
public static Method[] getPublicMethods(final Class<?> clazz, final String... excludeMethodNames) {
final HashSet<String> excludeMethodNameSet = CollUtil.newHashSet(excludeMethodNames);
return getPublicMethods(clazz, method -> false == excludeMethodNameSet.contains(method.getName()));
}
/**
* 查找指定Public方法 如果找不到对应的方法或方法不为public的则返回{@code null}
*
* @param clazz
* @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) {
return null;
}
}
/**
* 查找指定对象中的所有方法包括非public方法也包括父对象和Object类的方法
*
* <p>
* 此方法为精准获取方法名即方法名和参数数量和类型必须一致否则返回{@code null}
* </p>
*
* @param obj 被查找的对象如果为{@code null}返回{@code null}
* @param methodName 方法名如果为空字符串返回{@code null}
* @param args 参数
* @return 方法
* @throws SecurityException 无访问权限抛出异常
*/
public static Method getMethodOfObj(final Object obj, final String methodName, final Object... args) throws SecurityException {
if (null == obj || StrUtil.isBlank(methodName)) {
return null;
}
return getMethod(obj.getClass(), methodName, ClassUtil.getClasses(args));
}
/**
* 忽略大小写查找指定方法如果找不到对应的方法则返回{@code null}
*
* <p>
* 此方法为精准获取方法名即方法名和参数数量和类型必须一致否则返回{@code null}
* </p>
*
* @param clazz 如果为{@code null}返回{@code null}
* @param methodName 方法名如果为空字符串返回{@code null}
* @param paramTypes 参数类型指定参数类型如果是方法的子类也算
* @return 方法
* @throws SecurityException 无权访问抛出异常
* @since 3.2.0
*/
public static Method getMethodIgnoreCase(final Class<?> clazz, final String methodName, final Class<?>... paramTypes) throws SecurityException {
return getMethod(clazz, true, methodName, paramTypes);
}
/**
* 查找指定方法 如果找不到对应的方法则返回{@code null}
*
* <p>
* 此方法为精准获取方法名即方法名和参数数量和类型必须一致否则返回{@code null}
* </p>
*
* @param clazz 如果为{@code null}返回{@code null}
* @param methodName 方法名如果为空字符串返回{@code null}
* @param paramTypes 参数类型指定参数类型如果是方法的子类也算
* @return 方法
* @throws SecurityException 无权访问抛出异常
*/
public static Method getMethod(final Class<?> clazz, final String methodName, final Class<?>... paramTypes) throws SecurityException {
return getMethod(clazz, false, methodName, paramTypes);
}
/**
* 查找指定方法 如果找不到对应的方法则返回{@code null}<br>
* 此方法为精准获取方法名即方法名和参数数量和类型必须一致否则返回{@code null}<br>
* 如果查找的方法有多个同参数类型重载查找第一个找到的方法
*
* @param clazz 如果为{@code null}返回{@code null}
* @param ignoreCase 是否忽略大小写
* @param methodName 方法名如果为空字符串返回{@code null}
* @param paramTypes 参数类型指定参数类型如果是方法的子类也算
* @return 方法
* @throws SecurityException 无权访问抛出异常
* @since 3.2.0
*/
public static Method getMethod(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 = 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
&& false == method.isBridge()) {
return method;
}
}
}
return null;
}
/**
* 按照方法名查找指定方法名的方法只返回匹配到的第一个方法如果找不到对应的方法则返回{@code null}
*
* <p>
* 此方法只检查方法名是否一致并不检查参数的一致性
* </p>
*
* @param clazz 如果为{@code null}返回{@code null}
* @param methodName 方法名如果为空字符串返回{@code null}
* @return 方法
* @throws SecurityException 无权访问抛出异常
* @since 4.3.2
*/
public static Method getMethodByName(final Class<?> clazz, final String methodName) throws SecurityException {
return getMethodByName(clazz, false, methodName);
}
/**
* 按照方法名查找指定方法名的方法只返回匹配到的第一个方法如果找不到对应的方法则返回{@code null}
*
* <p>
* 此方法只检查方法名是否一致忽略大小写并不检查参数的一致性
* </p>
*
* @param clazz 如果为{@code null}返回{@code null}
* @param methodName 方法名如果为空字符串返回{@code null}
* @return 方法
* @throws SecurityException 无权访问抛出异常
* @since 4.3.2
*/
public static Method getMethodByNameIgnoreCase(final Class<?> clazz, final String methodName) throws SecurityException {
return getMethodByName(clazz, true, methodName);
}
/**
* 按照方法名查找指定方法名的方法只返回匹配到的第一个方法如果找不到对应的方法则返回{@code null}
*
* <p>
* 此方法只检查方法名是否一致并不检查参数的一致性
* </p>
*
* @param clazz 如果为{@code null}返回{@code null}
* @param ignoreCase 是否忽略大小写
* @param methodName 方法名如果为空字符串返回{@code null}
* @return 方法
* @throws SecurityException 无权访问抛出异常
* @since 4.3.2
*/
public static Method getMethodByName(final Class<?> clazz, final boolean ignoreCase, final String methodName) throws SecurityException {
if (null == clazz || StrUtil.isBlank(methodName)) {
return null;
}
final Method[] methods = getMethods(clazz);
if (ArrayUtil.isNotEmpty(methods)) {
for (final Method method : methods) {
if (StrUtil.equals(methodName, method.getName(), ignoreCase)
// 排除桥接方法
&& false == method.isBridge()) {
return method;
}
}
}
return null;
}
/**
* 获得指定类中的Public方法名<br>
* 去重重载的方法
*
* @param clazz
* @return 方法名Set
* @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;
}
/**
* 获得指定类过滤后的Public方法列表
*
* @param clazz 查找方法的类
* @param filter 过滤器
* @return 过滤后的方法列表
* @throws SecurityException 安全异常
*/
public static Method[] getMethods(final Class<?> clazz, final Filter<Method> filter) throws SecurityException {
if (null == clazz) {
return null;
}
return ArrayUtil.filter(getMethods(clazz), filter);
}
/**
* 获得一个类中所有方法列表包括其父类中的方法
*
* @param beanClass {@code null}
* @return 方法列表
* @throws SecurityException 安全检查异常
*/
public static Method[] getMethods(final Class<?> beanClass) throws SecurityException {
Assert.notNull(beanClass);
return METHODS_CACHE.computeIfAbsent(beanClass,
() -> getMethodsDirectly(beanClass, true, true));
}
/**
* 获得一个类中所有方法列表直接反射获取无缓存<br>
* 接口获取方法和默认方法获取的方法包括
* <ul>
* <li>本类中的所有方法包括static方法</li>
* <li>父类中的所有方法包括static方法</li>
* <li>Object中包括static方法</li>
* </ul>
*
* @param beanClass 类或接口
* @param withSupers 是否包括父类或接口的方法列表
* @param withMethodFromObject 是否包括Object中的方法
* @return 方法列表
* @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, ReflectUtil::getUniqueKey);
Class<?> searchType = beanClass;
while (searchType != null) {
if (false == withMethodFromObject && Object.class == searchType) {
break;
}
result.addAllIfAbsent(Arrays.asList(searchType.getDeclaredMethods()));
result.addAllIfAbsent(getDefaultMethodsFromInterface(searchType));
searchType = (withSupers && false == searchType.isInterface()) ? searchType.getSuperclass() : null;
}
return result.toArray(new Method[0]);
}
/**
* 是否为equals方法
*
* @param method 方法
* @return 是否为equals方法
*/
public static boolean isEqualsMethod(final Method method) {
if (method == null ||
1 != method.getParameterCount() ||
false == "equals".equals(method.getName())) {
return false;
}
return (method.getParameterTypes()[0] == Object.class);
}
/**
* 是否为hashCode方法
*
* @param method 方法
* @return 是否为hashCode方法
*/
public static boolean isHashCodeMethod(final Method method) {
return method != null//
&& "hashCode".equals(method.getName())//
&& isEmptyParam(method);
}
/**
* 是否为toString方法
*
* @param method 方法
* @return 是否为toString方法
*/
public static boolean isToStringMethod(final Method method) {
return method != null//
&& "toString".equals(method.getName())//
&& isEmptyParam(method);
}
/**
* 是否为无参数方法
*
* @param method 方法
* @return 是否为无参数方法
* @since 5.1.1
*/
public static boolean isEmptyParam(final Method method) {
return method.getParameterCount() == 0;
}
/**
* 检查给定方法是否为Getter或者Setter方法规则为<br>
* <ul>
* <li>方法参数必须为0个或1个</li>
* <li>如果是无参方法则判断是否以getis开头</li>
* <li>如果方法参数1个则判断是否以set开头</li>
* </ul>
*
* @param method 方法
* @return 是否为Getter或者Setter方法
* @since 5.7.20
*/
public static boolean isGetterOrSetterIgnoreCase(final Method method) {
return isGetterOrSetter(method, true);
}
/**
* 检查给定方法是否为Getter或者Setter方法规则为<br>
* <ul>
* <li>方法参数必须为0个或1个</li>
* <li>方法名称不能是getClass</li>
* <li>如果是无参方法则判断是否以getis开头</li>
* <li>如果方法参数1个则判断是否以set开头</li>
* </ul>
*
* @param method 方法
* @param ignoreCase 是否忽略方法名的大小写
* @return 是否为Getter或者Setter方法
* @since 5.7.20
*/
public static boolean isGetterOrSetter(final Method method, final boolean ignoreCase) {
if (null == method) {
return false;
}
// 参数个数必须为0或1
final int parameterCount = method.getParameterCount();
if (parameterCount > 1) {
return false;
}
String name = method.getName();
// 跳过getClass这个特殊方法
if ("getClass".equals(name)) {
return false;
}
if (ignoreCase) {
name = name.toLowerCase();
}
switch (parameterCount) {
case 0:
return name.startsWith("get") || name.startsWith("is");
case 1:
return name.startsWith("set");
default:
return false;
}
}
// --------------------------------------------------------------------------------------------------------- newInstance
/**
@ -927,142 +481,6 @@ public class ReflectUtil {
return null;
}
// --------------------------------------------------------------------------------------------------------- invoke
/**
* 执行静态方法
*
* @param <T> 对象类型
* @param method 方法对象方法或static方法都可
* @param args 参数对象
* @return 结果
* @throws UtilException 多种异常包装
*/
public static <T> T invokeStatic(final Method method, final Object... args) throws UtilException {
return invoke(null, method, args);
}
/**
* 执行方法<br>
* 执行前要检查给定参数
*
* <pre>
* 1. 参数个数是否与方法参数个数一致
* 2. 如果某个参数为null但是方法这个位置的参数为原始类型则赋予原始类型默认值
* </pre>
*
* @param <T> 返回对象类型
* @param obj 对象如果执行静态方法此值为{@code null}
* @param method 方法对象方法或static方法都可
* @param args 参数对象
* @return 结果
* @throws UtilException 一些列异常的包装
*/
public static <T> T invokeWithCheck(final Object obj, final Method method, final Object... args) throws UtilException {
final Class<?>[] types = method.getParameterTypes();
if (null != args) {
Assert.isTrue(args.length == types.length, "Params length [{}] is not fit for param length [{}] of method !", args.length, types.length);
Class<?> type;
for (int i = 0; i < args.length; i++) {
type = types[i];
if (type.isPrimitive() && null == args[i]) {
// 参数是原始类型而传入参数为null时赋予默认值
args[i] = ClassUtil.getDefaultValue(type);
}
}
}
return invoke(obj, method, args);
}
/**
* 执行方法
*
* <p>
* 对于用户传入参数会做必要检查包括
*
* <pre>
* 1忽略多余的参数
* 2参数不够补齐默认值
* 3传入参数为null但是目标参数类型为原始类型做转换
* </pre>
*
* @param <T> 返回对象类型
* @param obj 对象如果执行静态方法此值为{@code null}
* @param method 方法对象方法或static方法都可
* @param args 参数对象
* @return 结果
* @throws UtilException 一些列异常的包装
*/
@SuppressWarnings("unchecked")
public static <T> T invoke(final Object obj, final Method method, final Object... args) throws UtilException {
setAccessible(method);
// 检查用户传入参数
// 1忽略多余的参数
// 2参数不够补齐默认值
// 3通过NullWrapperBean传递的参数,会直接赋值null
// 4传入参数为null但是目标参数类型为原始类型做转换
// 5传入参数类型不对应尝试转换类型
final Class<?>[] parameterTypes = method.getParameterTypes();
final Object[] actualArgs = new Object[parameterTypes.length];
if (null != args) {
for (int i = 0; i < actualArgs.length; i++) {
if (i >= args.length || null == args[i]) {
// 越界或者空值
actualArgs[i] = ClassUtil.getDefaultValue(parameterTypes[i]);
} else if (args[i] instanceof NullWrapperBean) {
//如果是通过NullWrapperBean传递的null参数,直接赋值null
actualArgs[i] = null;
} else if (false == parameterTypes[i].isAssignableFrom(args[i].getClass())) {
//对于类型不同的字段尝试转换转换失败则使用原对象类型
final Object targetValue = Convert.convert(parameterTypes[i], args[i]);
if (null != targetValue) {
actualArgs[i] = targetValue;
}
} else {
actualArgs[i] = args[i];
}
}
}
if (method.isDefault()) {
// 当方法是default方法时尤其对象是代理对象需使用句柄方式执行
// 代理对象情况下调用method.invoke会导致循环引用执行最终栈溢出
return MethodHandleUtil.invokeSpecial(obj, method, args);
}
try {
return (T) method.invoke(ClassUtil.isStatic(method) ? null : obj, actualArgs);
} catch (final Exception e) {
throw new UtilException(e);
}
}
/**
* 执行对象中指定方法
* 如果需要传递的参数为null,请使用NullWrapperBean来传递,不然会丢失类型信息
*
* @param <T> 返回对象类型
* @param obj 方法所在对象
* @param methodName 方法名
* @param args 参数列表
* @return 执行结果
* @throws UtilException IllegalAccessException包装
* @see NullWrapperBean
* @since 3.1.2
*/
public static <T> T invoke(final Object obj, final String methodName, final Object... args) throws UtilException {
Assert.notNull(obj, "Object to get method must be not null!");
Assert.notBlank(methodName, "Method name must be not blank!");
final Method method = getMethodOfObj(obj, methodName, args);
if (null == method) {
throw new UtilException("No such method: [{}] from [{}]", methodName, obj.getClass());
}
return invoke(obj, method, args);
}
/**
* 设置方法为可访问私有方法可以被外部调用
*
@ -1077,47 +495,4 @@ public class ReflectUtil {
}
return accessibleObject;
}
/**
* 获取方法的唯一键结构为:
* <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 (false == ModifierUtil.isAbstract(m)) {
result.add(m);
}
}
}
return result;
}
}

View File

@ -9,9 +9,9 @@ import cn.hutool.core.lang.func.Func1;
import cn.hutool.core.lang.mutable.Mutable;
import cn.hutool.core.lang.mutable.MutableObj;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.reflect.ReflectUtil;
import cn.hutool.core.reflect.MethodUtil;
import cn.hutool.core.text.StrUtil;
import cn.hutool.core.util.ObjUtil;
import java.util.ArrayList;
import java.util.Collection;
@ -244,7 +244,7 @@ public class ReUtil {
final Map<String, String> result = MapUtil.newHashMap(m.groupCount());
if (m.find()) {
// 通过反射获取 namedGroups 方法
final Map<String, Integer> map = ReflectUtil.invoke(pattern, "namedGroups");
final Map<String, Integer> map = MethodUtil.invoke(pattern, "namedGroups");
map.forEach((key, value) -> result.put(key, m.group(value)));
}
return result;

View File

@ -5,10 +5,10 @@ import cn.hutool.core.comparator.CompareUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.exceptions.UtilException;
import cn.hutool.core.io.SerializeUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.math.NumberUtil;
import cn.hutool.core.reflect.ClassUtil;
import cn.hutool.core.reflect.ReflectUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.reflect.MethodUtil;
import cn.hutool.core.text.StrUtil;
import java.lang.reflect.Array;
@ -441,7 +441,7 @@ public class ObjUtil {
T result = ArrayUtil.clone(obj);
if (null == result) {
if (obj instanceof Cloneable) {
result = ReflectUtil.invoke(obj, "clone");
result = MethodUtil.invoke(obj, "clone");
} else {
result = cloneByStream(obj);
}

View File

@ -1,7 +1,5 @@
package cn.hutool.core.reflect;
import cn.hutool.core.reflect.MethodHandleUtil;
import cn.hutool.core.reflect.ReflectUtil;
import cn.hutool.core.classloader.ClassLoaderUtil;
import org.junit.Assert;
import org.junit.Test;
@ -23,12 +21,12 @@ public class MethodHandleUtilTest {
Assert.assertEquals("Quack", duck.quack());
// 测试子类执行default方法
final Method quackMethod = ReflectUtil.getMethod(Duck.class, "quack");
final Method quackMethod = MethodUtil.getMethod(Duck.class, "quack");
String quack = MethodHandleUtil.invokeSpecial(new BigDuck(), quackMethod);
Assert.assertEquals("Quack", quack);
// 测试反射执行默认方法
quack = ReflectUtil.invoke(new Duck() {}, quackMethod);
quack = MethodUtil.invoke(new Duck() {}, quackMethod);
Assert.assertEquals("Quack", quack);
}
@ -37,7 +35,7 @@ public class MethodHandleUtilTest {
final Duck duck = (Duck) Proxy.newProxyInstance(
ClassLoaderUtil.getClassLoader(),
new Class[] { Duck.class },
ReflectUtil::invoke);
MethodUtil::invoke);
Assert.assertEquals("Quack", duck.quack());
}
@ -47,7 +45,7 @@ public class MethodHandleUtilTest {
final Duck duck = (Duck) Proxy.newProxyInstance(
ClassLoaderUtil.getClassLoader(),
new Class[] { Duck.class },
ReflectUtil::invoke);
MethodUtil::invoke);
Assert.assertEquals("Quack", duck.quack());
}
@ -56,7 +54,7 @@ public class MethodHandleUtilTest {
public void invokeTest(){
// 测试执行普通方法
final int size = MethodHandleUtil.invokeSpecial(new BigDuck(),
ReflectUtil.getMethod(BigDuck.class, "getSize"));
MethodUtil.getMethod(BigDuck.class, "getSize"));
Assert.assertEquals(36, size);
}
@ -64,7 +62,7 @@ public class MethodHandleUtilTest {
public void invokeStaticTest(){
// 测试执行普通方法
final String result = MethodHandleUtil.invoke(null,
ReflectUtil.getMethod(Duck.class, "getDuck", int.class), 78);
MethodUtil.getMethod(Duck.class, "getDuck", int.class), 78);
Assert.assertEquals("Duck 78", result);
}

View File

@ -0,0 +1,169 @@
package cn.hutool.core.reflect;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.TimeInterval;
import cn.hutool.core.lang.Console;
import cn.hutool.core.lang.test.bean.ExamInfoDict;
import cn.hutool.core.text.StrUtil;
import cn.hutool.core.util.ArrayUtil;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
import java.lang.reflect.Method;
public class MethodUtilTest {
@Test
public void getMethodsTest() {
Method[] methods = MethodUtil.getMethods(ExamInfoDict.class);
Assert.assertEquals(20, methods.length);
//过滤器测试
methods = MethodUtil.getMethods(ExamInfoDict.class, t -> Integer.class.equals(t.getReturnType()));
Assert.assertEquals(4, methods.length);
final Method method = methods[0];
Assert.assertNotNull(method);
//null过滤器测试
methods = MethodUtil.getMethods(ExamInfoDict.class, null);
Assert.assertEquals(20, methods.length);
final Method method2 = methods[0];
Assert.assertNotNull(method2);
}
@Test
public void getMethodTest() {
Method method = MethodUtil.getMethod(ExamInfoDict.class, "getId");
Assert.assertEquals("getId", method.getName());
Assert.assertEquals(0, method.getParameterTypes().length);
method = MethodUtil.getMethod(ExamInfoDict.class, "getId", Integer.class);
Assert.assertEquals("getId", method.getName());
Assert.assertEquals(1, method.getParameterTypes().length);
}
@Test
public void getMethodIgnoreCaseTest() {
Method method = MethodUtil.getMethodIgnoreCase(ExamInfoDict.class, "getId");
Assert.assertEquals("getId", method.getName());
Assert.assertEquals(0, method.getParameterTypes().length);
method = MethodUtil.getMethodIgnoreCase(ExamInfoDict.class, "GetId");
Assert.assertEquals("getId", method.getName());
Assert.assertEquals(0, method.getParameterTypes().length);
method = MethodUtil.getMethodIgnoreCase(ExamInfoDict.class, "setanswerIs", Integer.class);
Assert.assertEquals("setAnswerIs", method.getName());
Assert.assertEquals(1, method.getParameterTypes().length);
}
@Test
public void invokeTest() {
final ReflectUtilTest.AClass testClass = new ReflectUtilTest.AClass();
MethodUtil.invoke(testClass, "setA", 10);
Assert.assertEquals(10, testClass.getA());
}
@Test
@Ignore
public void getMethodBenchTest() {
// 预热
getMethodWithReturnTypeCheck(ReflectUtilTest.TestBenchClass.class, false, "getH");
final TimeInterval timer = DateUtil.timer();
timer.start();
for (int i = 0; i < 100000000; i++) {
MethodUtil.getMethod(ReflectUtilTest.TestBenchClass.class, false, "getH");
}
Console.log(timer.interval());
timer.restart();
for (int i = 0; i < 100000000; i++) {
getMethodWithReturnTypeCheck(ReflectUtilTest.TestBenchClass.class, false, "getH");
}
Console.log(timer.interval());
}
public static Method getMethodWithReturnTypeCheck(final Class<?> clazz, final boolean ignoreCase, final String methodName, final Class<?>... paramTypes) throws SecurityException {
if (null == clazz || StrUtil.isBlank(methodName)) {
return null;
}
Method res = null;
final Method[] methods = MethodUtil.getMethods(clazz);
if (ArrayUtil.isNotEmpty(methods)) {
for (final Method method : methods) {
if (StrUtil.equals(methodName, method.getName(), ignoreCase)
&& ClassUtil.isAllAssignableFrom(method.getParameterTypes(), paramTypes)
&& (res == null
|| res.getReturnType().isAssignableFrom(method.getReturnType()))) {
res = method;
}
}
}
return res;
}
@Test
public void getMethodsFromClassExtends() {
// 继承情况下需解决方法去重问题
Method[] methods = MethodUtil.getMethods(ReflectUtilTest.C2.class);
Assert.assertEquals(15, methods.length);
// 排除Object中的方法
// 3个方法包括类
methods = MethodUtil.getMethodsDirectly(ReflectUtilTest.C2.class, true, false);
Assert.assertEquals(3, methods.length);
// getA属于本类
Assert.assertEquals("public void cn.hutool.core.reflect.ReflectUtilTest$C2.getA()", methods[0].toString());
// getB属于父类
Assert.assertEquals("public void cn.hutool.core.reflect.ReflectUtilTest$C1.getB()", methods[1].toString());
// getC属于接口中的默认方法
Assert.assertEquals("public default void cn.hutool.core.reflect.ReflectUtilTest$TestInterface1.getC()", methods[2].toString());
}
@Test
public void getMethodsFromInterfaceTest() {
// 对于接口直接调用Class.getMethods方法获取所有方法因为接口都是public方法
// 因此此处得到包括TestInterface1TestInterface2TestInterface3中一共4个方法
final Method[] methods = MethodUtil.getMethods(ReflectUtilTest.TestInterface3.class);
Assert.assertEquals(4, methods.length);
// 接口里调用getMethods和getPublicMethods效果相同
final Method[] publicMethods = MethodUtil.getPublicMethods(ReflectUtilTest.TestInterface3.class);
Assert.assertArrayEquals(methods, publicMethods);
}
@Test
public void getPublicMethod() {
final Method superPublicMethod = MethodUtil.getPublicMethod(ReflectUtilTest.TestSubClass.class, "publicMethod");
Assert.assertNotNull(superPublicMethod);
final Method superPrivateMethod = MethodUtil.getPublicMethod(ReflectUtilTest.TestSubClass.class, "privateMethod");
Assert.assertNull(superPrivateMethod);
final Method publicMethod = MethodUtil.getPublicMethod(ReflectUtilTest.TestSubClass.class, "publicSubMethod");
Assert.assertNotNull(publicMethod);
final Method privateMethod = MethodUtil.getPublicMethod(ReflectUtilTest.TestSubClass.class, "privateSubMethod");
Assert.assertNull(privateMethod);
}
@Test
public void getDeclaredMethod() {
final Method noMethod = MethodUtil.getMethod(ReflectUtilTest.TestSubClass.class, "noMethod");
Assert.assertNull(noMethod);
final Method privateMethod = MethodUtil.getMethod(ReflectUtilTest.TestSubClass.class, "privateMethod");
Assert.assertNotNull(privateMethod);
final Method publicMethod = MethodUtil.getMethod(ReflectUtilTest.TestSubClass.class, "publicMethod");
Assert.assertNotNull(publicMethod);
final Method publicSubMethod = MethodUtil.getMethod(ReflectUtilTest.TestSubClass.class, "publicSubMethod");
Assert.assertNotNull(publicSubMethod);
final Method privateSubMethod = MethodUtil.getMethod(ReflectUtilTest.TestSubClass.class, "privateSubMethod");
Assert.assertNotNull(privateSubMethod);
}
}

View File

@ -0,0 +1,178 @@
package cn.hutool.core.reflect;
import cn.hutool.core.date.Week;
import lombok.Data;
import org.junit.Assert;
import org.junit.Test;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Map;
/**
* 反射工具类单元测试
*
* @author Looly
*/
public class ReflectUtilTest {
@Test
public void getFieldTest() {
// 能够获取到父类字段
final Field privateField = ReflectUtil.getField(TestSubClass.class, "privateField");
Assert.assertNotNull(privateField);
}
@Test
public void getFieldsTest() {
// 能够获取到父类字段
final Field[] fields = ReflectUtil.getFields(TestSubClass.class);
Assert.assertEquals(4, fields.length);
}
@Test
public void setFieldTest() {
final AClass testClass = new AClass();
ReflectUtil.setFieldValue(testClass, "a", "111");
Assert.assertEquals(111, testClass.getA());
}
@Test
public void noneStaticInnerClassTest() {
final NoneStaticClass testAClass = ReflectUtil.newInstanceIfPossible(NoneStaticClass.class);
Assert.assertNotNull(testAClass);
Assert.assertEquals(2, testAClass.getA());
}
@Data
static class AClass {
private int a;
}
@Data
@SuppressWarnings("InnerClassMayBeStatic")
class NoneStaticClass {
private int a = 2;
}
@Data
static class TestBenchClass {
private int a;
private String b;
private String c;
private String d;
private String e;
private String f;
private String g;
private String h;
private String i;
private String j;
private String k;
private String l;
private String m;
private String n;
}
interface TestInterface1 {
@SuppressWarnings("unused")
void getA();
@SuppressWarnings("unused")
void getB();
@SuppressWarnings("unused")
default void getC() {
}
}
@SuppressWarnings("AbstractMethodOverridesAbstractMethod")
interface TestInterface2 extends TestInterface1 {
@Override
void getB();
}
interface TestInterface3 extends TestInterface2 {
void get3();
}
@SuppressWarnings("InnerClassMayBeStatic")
class C1 implements TestInterface2 {
@Override
public void getA() {
}
@Override
public void getB() {
}
}
class C2 extends C1 {
@Override
public void getA() {
}
}
@Test
public void newInstanceIfPossibleTest(){
//noinspection ConstantConditions
final int intValue = ReflectUtil.newInstanceIfPossible(int.class);
Assert.assertEquals(0, intValue);
final Integer integer = ReflectUtil.newInstanceIfPossible(Integer.class);
Assert.assertEquals(new Integer(0), integer);
final Map<?, ?> map = ReflectUtil.newInstanceIfPossible(Map.class);
Assert.assertNotNull(map);
final Collection<?> collection = ReflectUtil.newInstanceIfPossible(Collection.class);
Assert.assertNotNull(collection);
final Week week = ReflectUtil.newInstanceIfPossible(Week.class);
Assert.assertEquals(Week.SUNDAY, week);
final int[] intArray = ReflectUtil.newInstanceIfPossible(int[].class);
Assert.assertArrayEquals(new int[0], intArray);
}
@Test
public void getDeclaredField() {
final Field noField = ReflectUtil.getField(TestSubClass.class, "noField");
Assert.assertNull(noField);
// 获取不到父类字段
final Field field = ReflectUtil.getDeClearField(TestSubClass.class, "field");
Assert.assertNull(field);
final Field subField = ReflectUtil.getField(TestSubClass.class, "subField");
Assert.assertNotNull(subField);
}
@SuppressWarnings("unused")
static class TestClass {
private String privateField;
protected String field;
private void privateMethod() {
}
public void publicMethod() {
}
}
@SuppressWarnings({"InnerClassMayBeStatic", "unused"})
class TestSubClass extends TestClass {
private String subField;
private void privateSubMethod() {
}
public void publicSubMethod() {
}
}
}

View File

@ -1,341 +0,0 @@
package cn.hutool.core.util;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.TimeInterval;
import cn.hutool.core.date.Week;
import cn.hutool.core.lang.Console;
import cn.hutool.core.lang.test.bean.ExamInfoDict;
import cn.hutool.core.reflect.ClassUtil;
import cn.hutool.core.reflect.ReflectUtil;
import cn.hutool.core.text.StrUtil;
import lombok.Data;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Map;
/**
* 反射工具类单元测试
*
* @author Looly
*/
public class ReflectUtilTest {
@Test
public void getMethodsTest() {
Method[] methods = ReflectUtil.getMethods(ExamInfoDict.class);
Assert.assertEquals(20, methods.length);
//过滤器测试
methods = ReflectUtil.getMethods(ExamInfoDict.class, t -> Integer.class.equals(t.getReturnType()));
Assert.assertEquals(4, methods.length);
final Method method = methods[0];
Assert.assertNotNull(method);
//null过滤器测试
methods = ReflectUtil.getMethods(ExamInfoDict.class, null);
Assert.assertEquals(20, methods.length);
final Method method2 = methods[0];
Assert.assertNotNull(method2);
}
@Test
public void getMethodTest() {
Method method = ReflectUtil.getMethod(ExamInfoDict.class, "getId");
Assert.assertEquals("getId", method.getName());
Assert.assertEquals(0, method.getParameterTypes().length);
method = ReflectUtil.getMethod(ExamInfoDict.class, "getId", Integer.class);
Assert.assertEquals("getId", method.getName());
Assert.assertEquals(1, method.getParameterTypes().length);
}
@Test
public void getMethodIgnoreCaseTest() {
Method method = ReflectUtil.getMethodIgnoreCase(ExamInfoDict.class, "getId");
Assert.assertEquals("getId", method.getName());
Assert.assertEquals(0, method.getParameterTypes().length);
method = ReflectUtil.getMethodIgnoreCase(ExamInfoDict.class, "GetId");
Assert.assertEquals("getId", method.getName());
Assert.assertEquals(0, method.getParameterTypes().length);
method = ReflectUtil.getMethodIgnoreCase(ExamInfoDict.class, "setanswerIs", Integer.class);
Assert.assertEquals("setAnswerIs", method.getName());
Assert.assertEquals(1, method.getParameterTypes().length);
}
@Test
public void getFieldTest() {
// 能够获取到父类字段
final Field privateField = ReflectUtil.getField(TestSubClass.class, "privateField");
Assert.assertNotNull(privateField);
}
@Test
public void getFieldsTest() {
// 能够获取到父类字段
final Field[] fields = ReflectUtil.getFields(TestSubClass.class);
Assert.assertEquals(4, fields.length);
}
@Test
public void setFieldTest() {
final AClass testClass = new AClass();
ReflectUtil.setFieldValue(testClass, "a", "111");
Assert.assertEquals(111, testClass.getA());
}
@Test
public void invokeTest() {
final AClass testClass = new AClass();
ReflectUtil.invoke(testClass, "setA", 10);
Assert.assertEquals(10, testClass.getA());
}
@Test
public void noneStaticInnerClassTest() {
final NoneStaticClass testAClass = ReflectUtil.newInstanceIfPossible(NoneStaticClass.class);
Assert.assertNotNull(testAClass);
Assert.assertEquals(2, testAClass.getA());
}
@Data
static class AClass {
private int a;
}
@Data
@SuppressWarnings("InnerClassMayBeStatic")
class NoneStaticClass {
private int a = 2;
}
@Test
@Ignore
public void getMethodBenchTest() {
// 预热
getMethodWithReturnTypeCheck(TestBenchClass.class, false, "getH");
final TimeInterval timer = DateUtil.timer();
timer.start();
for (int i = 0; i < 100000000; i++) {
ReflectUtil.getMethod(TestBenchClass.class, false, "getH");
}
Console.log(timer.interval());
timer.restart();
for (int i = 0; i < 100000000; i++) {
getMethodWithReturnTypeCheck(TestBenchClass.class, false, "getH");
}
Console.log(timer.interval());
}
@Data
static class TestBenchClass {
private int a;
private String b;
private String c;
private String d;
private String e;
private String f;
private String g;
private String h;
private String i;
private String j;
private String k;
private String l;
private String m;
private String n;
}
public static Method getMethodWithReturnTypeCheck(final Class<?> clazz, final boolean ignoreCase, final String methodName, final Class<?>... paramTypes) throws SecurityException {
if (null == clazz || StrUtil.isBlank(methodName)) {
return null;
}
Method res = null;
final Method[] methods = ReflectUtil.getMethods(clazz);
if (ArrayUtil.isNotEmpty(methods)) {
for (final Method method : methods) {
if (StrUtil.equals(methodName, method.getName(), ignoreCase)
&& ClassUtil.isAllAssignableFrom(method.getParameterTypes(), paramTypes)
&& (res == null
|| res.getReturnType().isAssignableFrom(method.getReturnType()))) {
res = method;
}
}
}
return res;
}
@Test
public void getMethodsFromClassExtends() {
// 继承情况下需解决方法去重问题
Method[] methods = ReflectUtil.getMethods(C2.class);
Assert.assertEquals(15, methods.length);
// 排除Object中的方法
// 3个方法包括类
methods = ReflectUtil.getMethodsDirectly(C2.class, true, false);
Assert.assertEquals(3, methods.length);
// getA属于本类
Assert.assertEquals("public void cn.hutool.core.util.ReflectUtilTest$C2.getA()", methods[0].toString());
// getB属于父类
Assert.assertEquals("public void cn.hutool.core.util.ReflectUtilTest$C1.getB()", methods[1].toString());
// getC属于接口中的默认方法
Assert.assertEquals("public default void cn.hutool.core.util.ReflectUtilTest$TestInterface1.getC()", methods[2].toString());
}
@Test
public void getMethodsFromInterfaceTest() {
// 对于接口直接调用Class.getMethods方法获取所有方法因为接口都是public方法
// 因此此处得到包括TestInterface1TestInterface2TestInterface3中一共4个方法
final Method[] methods = ReflectUtil.getMethods(TestInterface3.class);
Assert.assertEquals(4, methods.length);
// 接口里调用getMethods和getPublicMethods效果相同
final Method[] publicMethods = ReflectUtil.getPublicMethods(TestInterface3.class);
Assert.assertArrayEquals(methods, publicMethods);
}
interface TestInterface1 {
@SuppressWarnings("unused")
void getA();
@SuppressWarnings("unused")
void getB();
@SuppressWarnings("unused")
default void getC() {
}
}
@SuppressWarnings("AbstractMethodOverridesAbstractMethod")
interface TestInterface2 extends TestInterface1 {
@Override
void getB();
}
interface TestInterface3 extends TestInterface2 {
void get3();
}
@SuppressWarnings("InnerClassMayBeStatic")
class C1 implements TestInterface2 {
@Override
public void getA() {
}
@Override
public void getB() {
}
}
class C2 extends C1 {
@Override
public void getA() {
}
}
@Test
public void newInstanceIfPossibleTest(){
//noinspection ConstantConditions
final int intValue = ReflectUtil.newInstanceIfPossible(int.class);
Assert.assertEquals(0, intValue);
final Integer integer = ReflectUtil.newInstanceIfPossible(Integer.class);
Assert.assertEquals(new Integer(0), integer);
final Map<?, ?> map = ReflectUtil.newInstanceIfPossible(Map.class);
Assert.assertNotNull(map);
final Collection<?> collection = ReflectUtil.newInstanceIfPossible(Collection.class);
Assert.assertNotNull(collection);
final Week week = ReflectUtil.newInstanceIfPossible(Week.class);
Assert.assertEquals(Week.SUNDAY, week);
final int[] intArray = ReflectUtil.newInstanceIfPossible(int[].class);
Assert.assertArrayEquals(new int[0], intArray);
}
@Test
public void getPublicMethod() {
final Method superPublicMethod = ReflectUtil.getPublicMethod(TestSubClass.class, "publicMethod");
Assert.assertNotNull(superPublicMethod);
final Method superPrivateMethod = ReflectUtil.getPublicMethod(TestSubClass.class, "privateMethod");
Assert.assertNull(superPrivateMethod);
final Method publicMethod = ReflectUtil.getPublicMethod(TestSubClass.class, "publicSubMethod");
Assert.assertNotNull(publicMethod);
final Method privateMethod = ReflectUtil.getPublicMethod(TestSubClass.class, "privateSubMethod");
Assert.assertNull(privateMethod);
}
@Test
public void getDeclaredMethod() {
final Method noMethod = ReflectUtil.getMethod(TestSubClass.class, "noMethod");
Assert.assertNull(noMethod);
final Method privateMethod = ReflectUtil.getMethod(TestSubClass.class, "privateMethod");
Assert.assertNotNull(privateMethod);
final Method publicMethod = ReflectUtil.getMethod(TestSubClass.class, "publicMethod");
Assert.assertNotNull(publicMethod);
final Method publicSubMethod = ReflectUtil.getMethod(TestSubClass.class, "publicSubMethod");
Assert.assertNotNull(publicSubMethod);
final Method privateSubMethod = ReflectUtil.getMethod(TestSubClass.class, "privateSubMethod");
Assert.assertNotNull(privateSubMethod);
}
@Test
public void getDeclaredField() {
final Field noField = ReflectUtil.getField(TestSubClass.class, "noField");
Assert.assertNull(noField);
// 获取不到父类字段
final Field field = ReflectUtil.getDeClearField(TestSubClass.class, "field");
Assert.assertNull(field);
final Field subField = ReflectUtil.getField(TestSubClass.class, "subField");
Assert.assertNotNull(subField);
}
@SuppressWarnings("unused")
static class TestClass {
private String privateField;
protected String field;
private void privateMethod() {
}
public void publicMethod() {
}
}
@SuppressWarnings({"InnerClassMayBeStatic", "unused"})
class TestSubClass extends TestClass {
private String subField;
private void privateSubMethod() {
}
public void publicSubMethod() {
}
}
}

View File

@ -1,5 +1,6 @@
package cn.hutool.core.util;
import cn.hutool.core.reflect.MethodUtil;
import cn.hutool.core.reflect.ReflectUtil;
import cn.hutool.core.reflect.TypeUtil;
import lombok.Data;
@ -15,7 +16,7 @@ public class TypeUtilTest {
@Test
public void getEleTypeTest() {
final Method method = ReflectUtil.getMethod(TestClass.class, "getList");
final Method method = MethodUtil.getMethod(TestClass.class, "getList");
final Type type = TypeUtil.getReturnType(method);
Assert.assertEquals("java.util.List<java.lang.String>", type.toString());
@ -25,7 +26,7 @@ public class TypeUtilTest {
@Test
public void getParamTypeTest() {
final Method method = ReflectUtil.getMethod(TestClass.class, "intTest", Integer.class);
final Method method = MethodUtil.getMethod(TestClass.class, "intTest", Integer.class);
final Type type = TypeUtil.getParamType(method, 0);
Assert.assertEquals(Integer.class, type);

View File

@ -2,6 +2,7 @@ package cn.hutool.cron.task;
import cn.hutool.core.classloader.ClassLoaderUtil;
import cn.hutool.core.exceptions.UtilException;
import cn.hutool.core.reflect.MethodUtil;
import cn.hutool.core.reflect.ReflectUtil;
import cn.hutool.core.text.StrUtil;
import cn.hutool.cron.CronException;
@ -50,7 +51,7 @@ public class InvokeTask implements Task{
if(StrUtil.isBlank(methodName)) {
throw new IllegalArgumentException("Method name is blank !");
}
this.method = ReflectUtil.getPublicMethod(clazz, methodName);
this.method = MethodUtil.getPublicMethod(clazz, methodName);
if(null == this.method) {
throw new IllegalArgumentException("No method with name of [" + methodName + "] !");
}
@ -59,7 +60,7 @@ public class InvokeTask implements Task{
@Override
public void execute() {
try {
ReflectUtil.invoke(this.obj, this.method);
MethodUtil.invoke(this.obj, this.method);
} catch (final UtilException e) {
throw new CronException(e.getCause());
}

View File

@ -3,7 +3,7 @@ package cn.hutool.db;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.func.Func0;
import cn.hutool.core.map.Dict;
import cn.hutool.core.reflect.ReflectUtil;
import cn.hutool.core.reflect.MethodUtil;
import cn.hutool.core.text.StrUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.CharsetUtil;
@ -301,7 +301,7 @@ public class Entity extends Dict {
result = (Time) obj;
} catch (final Exception e) {
// try oracle.sql.TIMESTAMP
result = ReflectUtil.invoke(obj, "timeValue");
result = MethodUtil.invoke(obj, "timeValue");
}
}
return result;
@ -316,7 +316,7 @@ public class Entity extends Dict {
result = (Date) obj;
} catch (final Exception e) {
// try oracle.sql.TIMESTAMP
result = ReflectUtil.invoke(obj, "dateValue");
result = MethodUtil.invoke(obj, "dateValue");
}
}
return result;
@ -331,7 +331,7 @@ public class Entity extends Dict {
result = (Timestamp) obj;
} catch (final Exception e) {
// try oracle.sql.TIMESTAMP
result = ReflectUtil.invoke(obj, "timestampValue");
result = MethodUtil.invoke(obj, "timestampValue");
}
}
return result;

View File

@ -4,6 +4,7 @@ import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.PropDesc;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.reflect.MethodUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.reflect.ReflectUtil;
import cn.hutool.core.text.StrUtil;
@ -100,7 +101,7 @@ public class ResultSetUtil {
setter = (null == pd) ? null : pd.getSetter();
if (null != setter) {
value = getColumnValue(rs, i, meta.getColumnType(i), TypeUtil.getFirstParamType(setter));
ReflectUtil.invokeWithCheck(bean, setter, value);
MethodUtil.invokeWithCheck(bean, setter, value);
}
}
return bean;

View File

@ -1,8 +1,8 @@
package cn.hutool.extra.aop.interceptor;
import cn.hutool.extra.aop.aspects.Aspect;
import cn.hutool.core.reflect.ClassUtil;
import cn.hutool.core.reflect.ModifierUtil;
import cn.hutool.core.reflect.ReflectUtil;
import cn.hutool.extra.aop.aspects.Aspect;
import java.io.Serializable;
import java.lang.reflect.InvocationHandler;
@ -47,7 +47,7 @@ public class JdkInterceptor implements InvocationHandler, Serializable {
ReflectUtil.setAccessible(method);
try {
result = method.invoke(ClassUtil.isStatic(method) ? null : target, args);
result = method.invoke(ModifierUtil.isStatic(method) ? null : target, args);
} catch (final InvocationTargetException e) {
// 异常回调只捕获业务代码导致的异常而非反射导致的异常
if (aspect.afterException(target, method, args, e.getTargetException())) {

View File

@ -2,9 +2,9 @@ package cn.hutool.poi.excel.sax;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.reflect.ReflectUtil;
import cn.hutool.core.reflect.MethodUtil;
import cn.hutool.core.text.StrUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.poi.excel.sax.handler.RowHandler;
import cn.hutool.poi.exceptions.POIException;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
@ -20,7 +20,7 @@ import java.util.Iterator;
/**
* Sax方式读取Excel文件<br>
* Excel2007格式说明见http://www.cnblogs.com/wangmingshun/p/6654143.html
* Excel2007格式说明见<a href="http://www.cnblogs.com/wangmingshun/p/6654143.html">http://www.cnblogs.com/wangmingshun/p/6654143.html</a>
*
* @author Looly
* @since 3.1.2
@ -130,7 +130,7 @@ public class Excel07SaxReader implements ExcelSaxReader<Excel07SaxReader> {
// 获取共享字符串表
// POI-5.2.0开始返回值有所变更导致实际使用时提示方法未找到此处使用反射调用解决不同版本返回值变更问题
//this.handler.sharedStrings = xssfReader.getSharedStringsTable();
this.handler.sharedStrings = ReflectUtil.invoke(xssfReader, "getSharedStringsTable");
this.handler.sharedStrings = MethodUtil.invoke(xssfReader, "getSharedStringsTable");
return readSheets(xssfReader, idOrRidOrSheetName);
}