mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-04-19 03:01:48 +08:00
fix code
This commit is contained in:
parent
b921895917
commit
56c076d2f6
@ -28,6 +28,16 @@ import java.lang.reflect.Method;
|
|||||||
*/
|
*/
|
||||||
public class MethodInvoker implements Invoker {
|
public class MethodInvoker implements Invoker {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建方法调用器
|
||||||
|
*
|
||||||
|
* @param method 方法
|
||||||
|
* @return 方法调用器
|
||||||
|
*/
|
||||||
|
public static MethodInvoker of(final Method method) {
|
||||||
|
return new MethodInvoker(method);
|
||||||
|
}
|
||||||
|
|
||||||
private final Method method;
|
private final Method method;
|
||||||
private final Class<?>[] paramTypes;
|
private final Class<?>[] paramTypes;
|
||||||
private final Class<?> type;
|
private final Class<?> type;
|
||||||
@ -43,6 +53,7 @@ public class MethodInvoker implements Invoker {
|
|||||||
|
|
||||||
this.paramTypes = method.getParameterTypes();
|
this.paramTypes = method.getParameterTypes();
|
||||||
if (paramTypes.length == 1) {
|
if (paramTypes.length == 1) {
|
||||||
|
// setter方法读取参数类型
|
||||||
type = paramTypes[0];
|
type = paramTypes[0];
|
||||||
} else {
|
} else {
|
||||||
type = method.getReturnType();
|
type = method.getReturnType();
|
||||||
@ -64,27 +75,44 @@ public class MethodInvoker implements Invoker {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
public <T> T invoke(final Object target, final Object... args) throws HutoolException{
|
public <T> T invoke(Object target, final Object... args) throws HutoolException{
|
||||||
if(this.checkArgs){
|
if(this.checkArgs){
|
||||||
checkArgs(args);
|
checkArgs(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final Method method = this.method;
|
||||||
|
// static方法调用则target为null
|
||||||
|
if(ModifierUtil.isStatic(method)){
|
||||||
|
target = null;
|
||||||
|
}
|
||||||
|
// 根据方法定义的参数类型,将用户传入的参数规整和转换
|
||||||
|
final Object[] actualArgs = MethodUtil.actualArgs(method, args);
|
||||||
try {
|
try {
|
||||||
return MethodHandleUtil.invoke(target, method, args);
|
return MethodHandleUtil.invokeExact(target, method, actualArgs);
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
// 传统反射方式执行方法
|
// 传统反射方式执行方法
|
||||||
try {
|
try {
|
||||||
return (T) method.invoke(ModifierUtil.isStatic(method) ? null : target, MethodUtil.actualArgs(method, args));
|
return (T) method.invoke(target, actualArgs);
|
||||||
} catch (final IllegalAccessException | InvocationTargetException ex) {
|
} catch (final IllegalAccessException | InvocationTargetException ex) {
|
||||||
throw new HutoolException(ex);
|
throw new HutoolException(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行静态方法
|
||||||
|
*
|
||||||
|
* @param <T> 对象类型
|
||||||
|
* @param args 参数对象
|
||||||
|
* @return 结果
|
||||||
|
* @throws HutoolException 多种异常包装
|
||||||
|
*/
|
||||||
|
public <T> T invokeStatic(final Object... args) throws HutoolException {
|
||||||
|
return invoke(null, args);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Class<?> getType() {
|
public Class<?> getType() {
|
||||||
return this.type;
|
return this.type;
|
||||||
|
@ -45,6 +45,13 @@ public class MethodUtil {
|
|||||||
*/
|
*/
|
||||||
private static final WeakConcurrentMap<Class<?>, MethodReflect> METHODS_CACHE = new WeakConcurrentMap<>();
|
private static final WeakConcurrentMap<Class<?>, MethodReflect> METHODS_CACHE = new WeakConcurrentMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清除方法缓存
|
||||||
|
*/
|
||||||
|
synchronized static void clearCache() {
|
||||||
|
METHODS_CACHE.clear();
|
||||||
|
}
|
||||||
|
|
||||||
// region ----- getMethods
|
// region ----- getMethods
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -255,7 +262,7 @@ public class MethodUtil {
|
|||||||
/**
|
/**
|
||||||
* 获得一个类中所有方法列表,包括其父类中的方法
|
* 获得一个类中所有方法列表,包括其父类中的方法
|
||||||
*
|
*
|
||||||
* @param clazz 类,非{@code null}
|
* @param clazz 类,非{@code null}
|
||||||
* @param predicate 方法过滤器,{@code null}表示无过滤
|
* @param predicate 方法过滤器,{@code null}表示无过滤
|
||||||
* @return 方法列表
|
* @return 方法列表
|
||||||
* @throws SecurityException 安全检查异常
|
* @throws SecurityException 安全检查异常
|
||||||
@ -267,7 +274,7 @@ public class MethodUtil {
|
|||||||
/**
|
/**
|
||||||
* 获得本类及其父类所有Public方法
|
* 获得本类及其父类所有Public方法
|
||||||
*
|
*
|
||||||
* @param clazz 查找方法的类
|
* @param clazz 查找方法的类
|
||||||
* @return 过滤后的方法列表
|
* @return 过滤后的方法列表
|
||||||
*/
|
*/
|
||||||
public static Method[] getPublicMethods(final Class<?> clazz) {
|
public static Method[] getPublicMethods(final Class<?> clazz) {
|
||||||
@ -288,7 +295,7 @@ public class MethodUtil {
|
|||||||
/**
|
/**
|
||||||
* 获得类中所有直接声明方法,不包括其父类中的方法
|
* 获得类中所有直接声明方法,不包括其父类中的方法
|
||||||
*
|
*
|
||||||
* @param clazz 类,非{@code null}
|
* @param clazz 类,非{@code null}
|
||||||
* @return 方法列表
|
* @return 方法列表
|
||||||
* @throws SecurityException 安全检查异常
|
* @throws SecurityException 安全检查异常
|
||||||
*/
|
*/
|
||||||
@ -529,7 +536,7 @@ public class MethodUtil {
|
|||||||
* @throws HutoolException 一些列异常的包装
|
* @throws HutoolException 一些列异常的包装
|
||||||
*/
|
*/
|
||||||
public static <T> T invokeWithCheck(final Object obj, final Method method, final Object... args) throws HutoolException {
|
public static <T> T invokeWithCheck(final Object obj, final Method method, final Object... args) throws HutoolException {
|
||||||
return (new MethodInvoker(method)).setCheckArgs(true).invoke(obj, args);
|
return MethodInvoker.of(method).setCheckArgs(true).invoke(obj, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -553,7 +560,7 @@ public class MethodUtil {
|
|||||||
* @see MethodHandleUtil#invoke(Object, Method, Object...)
|
* @see MethodHandleUtil#invoke(Object, Method, Object...)
|
||||||
*/
|
*/
|
||||||
public static <T> T invoke(final Object obj, final Method method, final Object... args) throws HutoolException {
|
public static <T> T invoke(final Object obj, final Method method, final Object... args) throws HutoolException {
|
||||||
return (new MethodInvoker(method)).invoke(obj, args);
|
return MethodInvoker.of(method).invoke(obj, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -26,7 +26,7 @@ import java.util.Map;
|
|||||||
public class ConstructorUtilTest {
|
public class ConstructorUtilTest {
|
||||||
@Test
|
@Test
|
||||||
public void noneStaticInnerClassTest() {
|
public void noneStaticInnerClassTest() {
|
||||||
final ReflectUtilTest.NoneStaticClass testAClass = ConstructorUtil.newInstanceIfPossible(ReflectUtilTest.NoneStaticClass.class);
|
final ReflectTestBeans.NoneStaticClass testAClass = ConstructorUtil.newInstanceIfPossible(ReflectTestBeans.NoneStaticClass.class);
|
||||||
Assertions.assertNotNull(testAClass);
|
Assertions.assertNotNull(testAClass);
|
||||||
Assertions.assertEquals(2, testAClass.getA());
|
Assertions.assertEquals(2, testAClass.getA());
|
||||||
}
|
}
|
||||||
|
@ -22,34 +22,34 @@ public class FieldUtilTest {
|
|||||||
@Test
|
@Test
|
||||||
public void getFieldTest() {
|
public void getFieldTest() {
|
||||||
// 能够获取到父类字段
|
// 能够获取到父类字段
|
||||||
final Field privateField = FieldUtil.getField(ReflectUtilTest.TestSubClass.class, "privateField");
|
final Field privateField = FieldUtil.getField(ReflectTestBeans.TestSubClass.class, "privateField");
|
||||||
Assertions.assertNotNull(privateField);
|
Assertions.assertNotNull(privateField);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getFieldsTest() {
|
public void getFieldsTest() {
|
||||||
// 能够获取到父类字段
|
// 能够获取到父类字段
|
||||||
final Field[] fields = FieldUtil.getFields(ReflectUtilTest.TestSubClass.class);
|
final Field[] fields = FieldUtil.getFields(ReflectTestBeans.TestSubClass.class);
|
||||||
Assertions.assertEquals(4, fields.length);
|
Assertions.assertEquals(4, fields.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void setFieldTest() {
|
public void setFieldTest() {
|
||||||
final ReflectUtilTest.AClass testClass = new ReflectUtilTest.AClass();
|
final ReflectTestBeans.AClass testClass = new ReflectTestBeans.AClass();
|
||||||
FieldUtil.setFieldValue(testClass, "a", "111");
|
FieldUtil.setFieldValue(testClass, "a", "111");
|
||||||
Assertions.assertEquals(111, testClass.getA());
|
Assertions.assertEquals(111, testClass.getA());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getDeclaredField() {
|
public void getDeclaredField() {
|
||||||
final Field noField = FieldUtil.getField(ReflectUtilTest.TestSubClass.class, "noField");
|
final Field noField = FieldUtil.getField(ReflectTestBeans.TestSubClass.class, "noField");
|
||||||
Assertions.assertNull(noField);
|
Assertions.assertNull(noField);
|
||||||
|
|
||||||
// 获取不到父类字段
|
// 获取不到父类字段
|
||||||
final Field field = FieldUtil.getDeclearField(ReflectUtilTest.TestSubClass.class, "field");
|
final Field field = FieldUtil.getDeclearField(ReflectTestBeans.TestSubClass.class, "field");
|
||||||
Assertions.assertNull(field);
|
Assertions.assertNull(field);
|
||||||
|
|
||||||
final Field subField = FieldUtil.getField(ReflectUtilTest.TestSubClass.class, "subField");
|
final Field subField = FieldUtil.getField(ReflectTestBeans.TestSubClass.class, "subField");
|
||||||
Assertions.assertNotNull(subField);
|
Assertions.assertNotNull(subField);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,6 +78,20 @@ public class MethodHandleUtilTest {
|
|||||||
Assertions.assertEquals("Duck 78", result);
|
Assertions.assertEquals("Duck 78", result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInvokeExact() {
|
||||||
|
final Duck duck = new BigDuck();
|
||||||
|
|
||||||
|
final Method method = MethodUtil.getMethod(BigDuck.class, "toString");
|
||||||
|
final Object[] args = {};
|
||||||
|
|
||||||
|
// 执行测试方法
|
||||||
|
final String result = MethodHandleUtil.invokeExact(duck, method, args);
|
||||||
|
|
||||||
|
// 验证结果
|
||||||
|
Assertions.assertEquals(duck.toString(), result);
|
||||||
|
}
|
||||||
|
|
||||||
interface Duck {
|
interface Duck {
|
||||||
default String quack() {
|
default String quack() {
|
||||||
return "Quack";
|
return "Quack";
|
||||||
@ -102,5 +116,10 @@ public class MethodHandleUtilTest {
|
|||||||
private static String getPrivateStaticValue(){
|
private static String getPrivateStaticValue(){
|
||||||
return "private static value";
|
return "private static value";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return super.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,14 +15,14 @@ package org.dromara.hutool.core.reflect;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 反射工具类单元测试
|
* 反射工具用于测试的类
|
||||||
*
|
*
|
||||||
* @author Looly
|
* @author Looly
|
||||||
*/
|
*/
|
||||||
public class ReflectUtilTest {
|
public class ReflectTestBeans {
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
static class AClass {
|
protected static class AClass {
|
||||||
private int a;
|
private int a;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,7 +33,7 @@ public class ReflectUtilTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
static class TestBenchClass {
|
protected static class TestBenchClass {
|
||||||
private int a;
|
private int a;
|
||||||
private String b;
|
private String b;
|
||||||
private String c;
|
private String c;
|
||||||
@ -69,7 +69,7 @@ public class ReflectUtilTest {
|
|||||||
void getB();
|
void getB();
|
||||||
}
|
}
|
||||||
|
|
||||||
interface TestInterface3 extends TestInterface2 {
|
protected interface TestInterface3 extends TestInterface2 {
|
||||||
void get3();
|
void get3();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,7 +88,7 @@ public class ReflectUtilTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("RedundantMethodOverride")
|
@SuppressWarnings("RedundantMethodOverride")
|
||||||
class C2 extends C1 {
|
protected class C2 extends C1 {
|
||||||
@Override
|
@Override
|
||||||
public void getA() {
|
public void getA() {
|
||||||
|
|
||||||
@ -108,7 +108,7 @@ public class ReflectUtilTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({"InnerClassMayBeStatic", "unused"})
|
@SuppressWarnings({"InnerClassMayBeStatic", "unused"})
|
||||||
class TestSubClass extends TestClass {
|
protected class TestSubClass extends TestClass {
|
||||||
private String subField;
|
private String subField;
|
||||||
|
|
||||||
private void privateSubMethod() {
|
private void privateSubMethod() {
|
@ -1,294 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2023 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 lombok.SneakyThrows;
|
|
||||||
import org.dromara.hutool.core.annotation.Alias;
|
|
||||||
import org.junit.jupiter.api.Assertions;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import java.lang.annotation.ElementType;
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.lang.annotation.RetentionPolicy;
|
|
||||||
import java.lang.annotation.Target;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* test for {@link MethodScanner2}
|
|
||||||
*
|
|
||||||
* @author huangchengxing
|
|
||||||
*/
|
|
||||||
class MethodScannerTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testGetMethods() {
|
|
||||||
Assertions.assertEquals(0, MethodScanner2.getMethods(null).length);
|
|
||||||
final Method[] actual = MethodScanner2.getMethods(Child.class);
|
|
||||||
Assertions.assertSame(actual, MethodScanner2.getMethods(Child.class));
|
|
||||||
final Method[] expected = Child.class.getMethods();
|
|
||||||
Assertions.assertArrayEquals(expected, actual);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testGetDeclaredMethods() {
|
|
||||||
Assertions.assertEquals(0, MethodScanner2.getDeclaredMethods(null).length);
|
|
||||||
final Method[] actual = MethodScanner2.getDeclaredMethods(Child.class);
|
|
||||||
Assertions.assertSame(actual, MethodScanner2.getDeclaredMethods(Child.class));
|
|
||||||
final Method[] expected = Child.class.getDeclaredMethods();
|
|
||||||
Assertions.assertArrayEquals(expected, actual);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testGetAllMethods() {
|
|
||||||
Assertions.assertEquals(0, MethodScanner2.getAllMethods(null).length);
|
|
||||||
final Method[] actual = MethodScanner2.getAllMethods(Child.class);
|
|
||||||
// get declared method from child、parent、grandparent
|
|
||||||
final Method[] expected = Stream.of(Child.class, Parent.class, Interface.class, Object.class)
|
|
||||||
.flatMap(c -> Stream.of(MethodScanner2.getDeclaredMethods(c)))
|
|
||||||
.toArray(Method[]::new);
|
|
||||||
Assertions.assertArrayEquals(expected, actual);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testClearCaches() {
|
|
||||||
final Method[] declaredMethods = MethodScanner2.getDeclaredMethods(Child.class);
|
|
||||||
Assertions.assertSame(declaredMethods, MethodScanner2.getDeclaredMethods(Child.class));
|
|
||||||
final Method[] methods = MethodScanner2.getMethods(Child.class);
|
|
||||||
Assertions.assertSame(methods, MethodScanner2.getMethods(Child.class));
|
|
||||||
|
|
||||||
// clear method cache
|
|
||||||
MethodScanner2.clearCaches();
|
|
||||||
Assertions.assertNotSame(declaredMethods, MethodScanner2.getDeclaredMethods(Child.class));
|
|
||||||
Assertions.assertNotSame(methods, MethodScanner2.getMethods(Child.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
@SneakyThrows
|
|
||||||
@Test
|
|
||||||
void testFindWithMetadataFromSpecificMethods() {
|
|
||||||
Assertions.assertTrue(MethodScanner2.findWithMetadataFromSpecificMethods(null, m -> m.getAnnotation(Annotation.class)).isEmpty());
|
|
||||||
final Method[] methods = MethodScanner2.getMethods(Child.class);
|
|
||||||
final Map<Method, Annotation> actual = MethodScanner2.findWithMetadataFromSpecificMethods(methods, m -> m.getAnnotation(Annotation.class));
|
|
||||||
Assertions.assertEquals(1, actual.size());
|
|
||||||
|
|
||||||
// check method
|
|
||||||
final Method expectedMethod = Parent.class.getDeclaredMethod("oneArgMethod", String.class);
|
|
||||||
Assertions.assertTrue(actual.containsKey(expectedMethod));
|
|
||||||
|
|
||||||
// check annotation
|
|
||||||
final Annotation expectedAnnotation = expectedMethod.getAnnotation(Annotation.class);
|
|
||||||
Assertions.assertEquals(expectedAnnotation, actual.get(expectedMethod));
|
|
||||||
}
|
|
||||||
|
|
||||||
@SneakyThrows
|
|
||||||
@Test
|
|
||||||
void testFindFromSpecificMethods() {
|
|
||||||
final Method[] methods = MethodScanner2.getMethods(Child.class);
|
|
||||||
final Set<Method> actual = MethodScanner2.findFromSpecificMethods(methods, m -> m.getAnnotation(Annotation.class));
|
|
||||||
Assertions.assertEquals(1, actual.size());
|
|
||||||
|
|
||||||
// check method
|
|
||||||
final Method expectedMethod = Parent.class.getDeclaredMethod("oneArgMethod", String.class);
|
|
||||||
Assertions.assertTrue(actual.contains(expectedMethod));
|
|
||||||
}
|
|
||||||
|
|
||||||
@SneakyThrows
|
|
||||||
@Test
|
|
||||||
void testGetWithMetadataFromSpecificMethods() {
|
|
||||||
// find first oneArgMethod method
|
|
||||||
final Method[] methods = MethodScanner2.getMethods(Child.class);
|
|
||||||
final Map.Entry<Method, Boolean> actual = MethodScanner2.getWithMetadataFromSpecificMethods(methods,
|
|
||||||
(method -> method.getName().equals("oneArgMethod") ? true : null));
|
|
||||||
Assertions.assertNotNull(actual);
|
|
||||||
final Method expectedMethod = Parent.class.getDeclaredMethod("oneArgMethod", String.class);
|
|
||||||
Assertions.assertEquals(expectedMethod, actual.getKey());
|
|
||||||
Assertions.assertTrue(actual.getValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
@SneakyThrows
|
|
||||||
@Test
|
|
||||||
void testGetFromSpecificMethods() {
|
|
||||||
// find first oneArgMethod method
|
|
||||||
final Method[] methods = MethodScanner2.getMethods(Child.class);
|
|
||||||
final Method actual = MethodScanner2.getFromSpecificMethods(methods, method ->
|
|
||||||
method.getName().equals("oneArgMethod") ? true : null);
|
|
||||||
final Method expectedMethod = Parent.class.getDeclaredMethod("oneArgMethod", String.class);
|
|
||||||
Assertions.assertEquals(expectedMethod, actual);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SneakyThrows
|
|
||||||
@Test
|
|
||||||
void testFindWithMetadataFromMethods() {
|
|
||||||
final Map<Method, Annotation> actual = MethodScanner2.findWithMetadataFromMethods(Child.class, m -> m.getAnnotation(Annotation.class));
|
|
||||||
Assertions.assertEquals(1, actual.size());
|
|
||||||
|
|
||||||
// check method
|
|
||||||
final Method expectedMethod = Parent.class.getDeclaredMethod("oneArgMethod", String.class);
|
|
||||||
Assertions.assertTrue(actual.containsKey(expectedMethod));
|
|
||||||
|
|
||||||
// check annotation
|
|
||||||
final Annotation expectedAnnotation = expectedMethod.getAnnotation(Annotation.class);
|
|
||||||
Assertions.assertEquals(expectedAnnotation, actual.get(expectedMethod));
|
|
||||||
}
|
|
||||||
|
|
||||||
@SneakyThrows
|
|
||||||
@Test
|
|
||||||
void testFindFromMethods() {
|
|
||||||
final Set<Method> actual = MethodScanner2.findFromMethods(Child.class, m -> m.getAnnotation(Annotation.class));
|
|
||||||
Assertions.assertEquals(1, actual.size());
|
|
||||||
|
|
||||||
// check method
|
|
||||||
final Method expectedMethod = Parent.class.getDeclaredMethod("oneArgMethod", String.class);
|
|
||||||
Assertions.assertTrue(actual.contains(expectedMethod));
|
|
||||||
}
|
|
||||||
|
|
||||||
@SneakyThrows
|
|
||||||
@Test
|
|
||||||
void testGetWithMetadataFromMethods() {
|
|
||||||
final Map.Entry<Method, Annotation> actual = MethodScanner2.getWithMetadataFromMethods(Child.class, m -> m.getAnnotation(Annotation.class));
|
|
||||||
Assertions.assertNotNull(actual);
|
|
||||||
final Method expectedMethod = Parent.class.getDeclaredMethod("oneArgMethod", String.class);
|
|
||||||
Assertions.assertEquals(expectedMethod, actual.getKey());
|
|
||||||
final Annotation expectedAnnotation = expectedMethod.getAnnotation(Annotation.class);
|
|
||||||
Assertions.assertEquals(expectedAnnotation, actual.getValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
@SneakyThrows
|
|
||||||
@Test
|
|
||||||
void testGetFromMethods() {
|
|
||||||
final Method actual = MethodScanner2.getFromMethods(Child.class, m -> m.getAnnotation(Annotation.class));
|
|
||||||
final Method expectedMethod = Parent.class.getDeclaredMethod("oneArgMethod", String.class);
|
|
||||||
Assertions.assertEquals(expectedMethod, actual);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SneakyThrows
|
|
||||||
@Test
|
|
||||||
void testFindWithMetadataFromDeclaredMethods() {
|
|
||||||
final Map<Method, Annotation> actual = MethodScanner2.findWithMetadataFromDeclaredMethods(Parent.class, m -> m.getAnnotation(Annotation.class));
|
|
||||||
Assertions.assertEquals(1, actual.size());
|
|
||||||
|
|
||||||
// check method
|
|
||||||
final Method expectedMethod = Parent.class.getDeclaredMethod("oneArgMethod", String.class);
|
|
||||||
Assertions.assertTrue(actual.containsKey(expectedMethod));
|
|
||||||
|
|
||||||
// check annotation
|
|
||||||
final Annotation expectedAnnotation = expectedMethod.getAnnotation(Annotation.class);
|
|
||||||
Assertions.assertEquals(expectedAnnotation, actual.get(expectedMethod));
|
|
||||||
}
|
|
||||||
|
|
||||||
@SneakyThrows
|
|
||||||
@Test
|
|
||||||
void testFindFromDeclaredMethods() {
|
|
||||||
final Set<Method> actual = MethodScanner2.findFromDeclaredMethods(Parent.class, m -> m.getAnnotation(Annotation.class));
|
|
||||||
Assertions.assertEquals(1, actual.size());
|
|
||||||
|
|
||||||
// check method
|
|
||||||
final Method expectedMethod = Parent.class.getDeclaredMethod("oneArgMethod", String.class);
|
|
||||||
Assertions.assertTrue(actual.contains(expectedMethod));
|
|
||||||
}
|
|
||||||
|
|
||||||
@SneakyThrows
|
|
||||||
@Test
|
|
||||||
void testGetWithMetadataFromDeclaredMethods() {
|
|
||||||
final Map.Entry<Method, Annotation> actual = MethodScanner2.getWithMetadataFromDeclaredMethods(Parent.class, m -> m.getAnnotation(Annotation.class));
|
|
||||||
Assertions.assertNotNull(actual);
|
|
||||||
final Method expectedMethod = Parent.class.getDeclaredMethod("oneArgMethod", String.class);
|
|
||||||
Assertions.assertEquals(expectedMethod, actual.getKey());
|
|
||||||
final Annotation expectedAnnotation = expectedMethod.getAnnotation(Annotation.class);
|
|
||||||
Assertions.assertEquals(expectedAnnotation, actual.getValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
@SneakyThrows
|
|
||||||
@Test
|
|
||||||
void testGetFromDeclaredMethods() {
|
|
||||||
final Method actual = MethodScanner2.getFromDeclaredMethods(Parent.class, m -> m.getAnnotation(Annotation.class));
|
|
||||||
final Method expectedMethod = Parent.class.getDeclaredMethod("oneArgMethod", String.class);
|
|
||||||
Assertions.assertEquals(expectedMethod, actual);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SneakyThrows
|
|
||||||
@Test
|
|
||||||
void testFindWithMetadataFromAllMethods() {
|
|
||||||
final Map<Method, Annotation> actual = MethodScanner2.findWithMetadataFromAllMethods(Child.class, m -> m.getAnnotation(Annotation.class));
|
|
||||||
Assertions.assertEquals(1, actual.size());
|
|
||||||
|
|
||||||
// check method
|
|
||||||
final Method expectedMethod = Parent.class.getDeclaredMethod("oneArgMethod", String.class);
|
|
||||||
Assertions.assertTrue(actual.containsKey(expectedMethod));
|
|
||||||
|
|
||||||
// check annotation
|
|
||||||
final Annotation expectedAnnotation = expectedMethod.getAnnotation(Annotation.class);
|
|
||||||
Assertions.assertEquals(expectedAnnotation, actual.get(expectedMethod));
|
|
||||||
}
|
|
||||||
|
|
||||||
@SneakyThrows
|
|
||||||
@Test
|
|
||||||
void testFindFromAllMethods() {
|
|
||||||
final Set<Method> actual = MethodScanner2.findFromAllMethods(Child.class, m -> m.getAnnotation(Annotation.class));
|
|
||||||
Assertions.assertEquals(1, actual.size());
|
|
||||||
|
|
||||||
// check method
|
|
||||||
final Method expectedMethod = Parent.class.getDeclaredMethod("oneArgMethod", String.class);
|
|
||||||
Assertions.assertTrue(actual.contains(expectedMethod));
|
|
||||||
}
|
|
||||||
|
|
||||||
@SneakyThrows
|
|
||||||
@Test
|
|
||||||
void testGetWithMetadataFromAllMethods() {
|
|
||||||
Assertions.assertNull(MethodScanner2.getWithMetadataFromAllMethods(Child.class, m -> m.getAnnotation(Alias.class)));
|
|
||||||
final Map.Entry<Method, Annotation> actual = MethodScanner2.getWithMetadataFromAllMethods(Child.class, m -> m.getAnnotation(Annotation.class));
|
|
||||||
Assertions.assertNotNull(actual);
|
|
||||||
final Method expectedMethod = Parent.class.getDeclaredMethod("oneArgMethod", String.class);
|
|
||||||
Assertions.assertEquals(expectedMethod, actual.getKey());
|
|
||||||
final Annotation expectedAnnotation = expectedMethod.getAnnotation(Annotation.class);
|
|
||||||
Assertions.assertEquals(expectedAnnotation, actual.getValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
@SneakyThrows
|
|
||||||
@Test
|
|
||||||
void testGetFromAllMethods() {
|
|
||||||
final Method actual = MethodScanner2.getFromAllMethods(Child.class, m -> m.getAnnotation(Annotation.class));
|
|
||||||
final Method expectedMethod = Parent.class.getDeclaredMethod("oneArgMethod", String.class);
|
|
||||||
Assertions.assertEquals(expectedMethod, actual);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Target({ElementType.METHOD, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
public @interface Annotation {
|
|
||||||
String value() default "default";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Annotation("Interface")
|
|
||||||
public interface Interface {
|
|
||||||
static void staticMethod() {
|
|
||||||
|
|
||||||
}
|
|
||||||
void noneArgMethod();
|
|
||||||
void oneArgMethod(String arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class Parent implements Interface {
|
|
||||||
@Override
|
|
||||||
public void noneArgMethod() { }
|
|
||||||
|
|
||||||
@Annotation("oneArgMethod")
|
|
||||||
@Override
|
|
||||||
public void oneArgMethod(final String arg) { }
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class Child extends Parent implements Interface {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -10,14 +10,15 @@
|
|||||||
* See the Mulan PSL v2 for more details.
|
* See the Mulan PSL v2 for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.dromara.hutool.core.reflect;
|
package org.dromara.hutool.core.reflect.method;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import org.dromara.hutool.core.array.ArrayUtil;
|
import org.dromara.hutool.core.array.ArrayUtil;
|
||||||
import org.dromara.hutool.core.date.StopWatch;
|
import org.dromara.hutool.core.date.StopWatch;
|
||||||
import org.dromara.hutool.core.lang.Console;
|
import org.dromara.hutool.core.lang.Console;
|
||||||
import org.dromara.hutool.core.lang.test.bean.ExamInfoDict;
|
import org.dromara.hutool.core.lang.test.bean.ExamInfoDict;
|
||||||
import org.dromara.hutool.core.reflect.method.MethodUtil;
|
import org.dromara.hutool.core.reflect.ClassUtil;
|
||||||
|
import org.dromara.hutool.core.reflect.ReflectTestBeans;
|
||||||
import org.dromara.hutool.core.text.StrUtil;
|
import org.dromara.hutool.core.text.StrUtil;
|
||||||
import org.dromara.hutool.core.util.JdkUtil;
|
import org.dromara.hutool.core.util.JdkUtil;
|
||||||
import org.junit.jupiter.api.Assertions;
|
import org.junit.jupiter.api.Assertions;
|
||||||
@ -26,7 +27,7 @@ import org.junit.jupiter.api.Test;
|
|||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
public class MethodUtilTest {
|
public class MethodUtilTest extends ReflectTestBeans {
|
||||||
|
|
||||||
private static final boolean isGteJdk15 = getJavaVersion() >= 15;
|
private static final boolean isGteJdk15 = getJavaVersion() >= 15;
|
||||||
/**
|
/**
|
||||||
@ -87,14 +88,14 @@ public class MethodUtilTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void invokeTest() {
|
public void invokeTest() {
|
||||||
final ReflectUtilTest.AClass testClass = new ReflectUtilTest.AClass();
|
final AClass testClass = new AClass();
|
||||||
MethodUtil.invoke(testClass, "setA", 10);
|
MethodUtil.invoke(testClass, "setA", 10);
|
||||||
Assertions.assertEquals(10, testClass.getA());
|
Assertions.assertEquals(10, testClass.getA());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getDeclaredMethodsTest() {
|
public void getDeclaredMethodsTest() {
|
||||||
Class<?> type = ReflectUtilTest.TestBenchClass.class;
|
Class<?> type = TestBenchClass.class;
|
||||||
Method[] methods = type.getDeclaredMethods();
|
Method[] methods = type.getDeclaredMethods();
|
||||||
Assertions.assertArrayEquals(methods, MethodUtil.getDeclaredMethods(type));
|
Assertions.assertArrayEquals(methods, MethodUtil.getDeclaredMethods(type));
|
||||||
Assertions.assertSame(MethodUtil.getDeclaredMethods(type), MethodUtil.getDeclaredMethods(type));
|
Assertions.assertSame(MethodUtil.getDeclaredMethods(type), MethodUtil.getDeclaredMethods(type));
|
||||||
@ -108,19 +109,19 @@ public class MethodUtilTest {
|
|||||||
@Disabled
|
@Disabled
|
||||||
public void getMethodBenchTest() {
|
public void getMethodBenchTest() {
|
||||||
// 预热
|
// 预热
|
||||||
getMethodWithReturnTypeCheck(ReflectUtilTest.TestBenchClass.class, false, "getH");
|
getMethodWithReturnTypeCheck(TestBenchClass.class, false, "getH");
|
||||||
|
|
||||||
final StopWatch timer = new StopWatch();
|
final StopWatch timer = new StopWatch();
|
||||||
timer.start();
|
timer.start();
|
||||||
for (int i = 0; i < 100000000; i++) {
|
for (int i = 0; i < 100000000; i++) {
|
||||||
MethodUtil.getMethod(ReflectUtilTest.TestBenchClass.class, false, "getH");
|
MethodUtil.getMethod(TestBenchClass.class, false, "getH");
|
||||||
}
|
}
|
||||||
timer.stop();
|
timer.stop();
|
||||||
Console.log(timer.getLastTaskTimeMillis());
|
Console.log(timer.getLastTaskTimeMillis());
|
||||||
|
|
||||||
timer.start();
|
timer.start();
|
||||||
for (int i = 0; i < 100000000; i++) {
|
for (int i = 0; i < 100000000; i++) {
|
||||||
getMethodWithReturnTypeCheck(ReflectUtilTest.TestBenchClass.class, false, "getH");
|
getMethodWithReturnTypeCheck(TestBenchClass.class, false, "getH");
|
||||||
}
|
}
|
||||||
timer.stop();
|
timer.stop();
|
||||||
Console.log(timer.getLastTaskTimeMillis());
|
Console.log(timer.getLastTaskTimeMillis());
|
||||||
@ -150,60 +151,60 @@ public class MethodUtilTest {
|
|||||||
@Test
|
@Test
|
||||||
public void getMethodsFromClassExtends() {
|
public void getMethodsFromClassExtends() {
|
||||||
// 继承情况下,需解决方法去重问题
|
// 继承情况下,需解决方法去重问题
|
||||||
Method[] methods = MethodUtil.getMethods(ReflectUtilTest.C2.class);
|
Method[] methods = MethodUtil.getMethods(C2.class);
|
||||||
Assertions.assertEquals(isGteJdk15 ? 14 : 15, methods.length);
|
Assertions.assertEquals(isGteJdk15 ? 14 : 15, methods.length);
|
||||||
|
|
||||||
// 排除Object中的方法
|
// 排除Object中的方法
|
||||||
// 3个方法包括类
|
// 3个方法包括类
|
||||||
methods = MethodUtil.getMethodsDirectly(ReflectUtilTest.C2.class, true, false);
|
methods = MethodUtil.getMethodsDirectly(C2.class, true, false);
|
||||||
Assertions.assertEquals(3, methods.length);
|
Assertions.assertEquals(3, methods.length);
|
||||||
|
|
||||||
// getA属于本类
|
// getA属于本类
|
||||||
Assertions.assertEquals("public void org.dromara.hutool.core.reflect.ReflectUtilTest$C2.getA()", methods[0].toString());
|
Assertions.assertEquals("public void org.dromara.hutool.core.reflect.ReflectTestBeans$C2.getA()", methods[0].toString());
|
||||||
// getB属于父类
|
// getB属于父类
|
||||||
Assertions.assertEquals("public void org.dromara.hutool.core.reflect.ReflectUtilTest$C1.getB()", methods[1].toString());
|
Assertions.assertEquals("public void org.dromara.hutool.core.reflect.ReflectTestBeans$C1.getB()", methods[1].toString());
|
||||||
// getC属于接口中的默认方法
|
// getC属于接口中的默认方法
|
||||||
Assertions.assertEquals("public default void org.dromara.hutool.core.reflect.ReflectUtilTest$TestInterface1.getC()", methods[2].toString());
|
Assertions.assertEquals("public default void org.dromara.hutool.core.reflect.ReflectTestBeans$TestInterface1.getC()", methods[2].toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getMethodsFromInterfaceTest() {
|
public void getMethodsFromInterfaceTest() {
|
||||||
// 对于接口,直接调用Class.getMethods方法获取所有方法,因为接口都是public方法
|
// 对于接口,直接调用Class.getMethods方法获取所有方法,因为接口都是public方法
|
||||||
// 因此此处得到包括TestInterface1、TestInterface2、TestInterface3中一共4个方法
|
// 因此此处得到包括TestInterface1、TestInterface2、TestInterface3中一共4个方法
|
||||||
final Method[] methods = MethodUtil.getMethods(ReflectUtilTest.TestInterface3.class);
|
final Method[] methods = MethodUtil.getMethods(TestInterface3.class);
|
||||||
Assertions.assertEquals(4, methods.length);
|
Assertions.assertEquals(4, methods.length);
|
||||||
|
|
||||||
// 接口里,调用getMethods和getPublicMethods效果相同
|
// 接口里,调用getMethods和getPublicMethods效果相同
|
||||||
final Method[] publicMethods = MethodUtil.getPublicMethods(ReflectUtilTest.TestInterface3.class);
|
final Method[] publicMethods = MethodUtil.getPublicMethods(TestInterface3.class);
|
||||||
Assertions.assertArrayEquals(methods, publicMethods);
|
Assertions.assertArrayEquals(methods, publicMethods);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getPublicMethod() {
|
public void getPublicMethod() {
|
||||||
final Method superPublicMethod = MethodUtil.getPublicMethod(ReflectUtilTest.TestSubClass.class, false, "publicMethod");
|
final Method superPublicMethod = MethodUtil.getPublicMethod(TestSubClass.class, false, "publicMethod");
|
||||||
Assertions.assertNotNull(superPublicMethod);
|
Assertions.assertNotNull(superPublicMethod);
|
||||||
final Method superPrivateMethod = MethodUtil.getPublicMethod(ReflectUtilTest.TestSubClass.class, false, "privateMethod");
|
final Method superPrivateMethod = MethodUtil.getPublicMethod(TestSubClass.class, false, "privateMethod");
|
||||||
Assertions.assertNull(superPrivateMethod);
|
Assertions.assertNull(superPrivateMethod);
|
||||||
|
|
||||||
final Method publicMethod = MethodUtil.getPublicMethod(ReflectUtilTest.TestSubClass.class, false, "publicSubMethod");
|
final Method publicMethod = MethodUtil.getPublicMethod(TestSubClass.class, false, "publicSubMethod");
|
||||||
Assertions.assertNotNull(publicMethod);
|
Assertions.assertNotNull(publicMethod);
|
||||||
final Method privateMethod = MethodUtil.getPublicMethod(ReflectUtilTest.TestSubClass.class, false, "privateSubMethod");
|
final Method privateMethod = MethodUtil.getPublicMethod(TestSubClass.class, false, "privateSubMethod");
|
||||||
Assertions.assertNull(privateMethod);
|
Assertions.assertNull(privateMethod);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getDeclaredMethod() {
|
public void getDeclaredMethod() {
|
||||||
final Method noMethod = MethodUtil.getMethod(ReflectUtilTest.TestSubClass.class, "noMethod");
|
final Method noMethod = MethodUtil.getMethod(TestSubClass.class, "noMethod");
|
||||||
Assertions.assertNull(noMethod);
|
Assertions.assertNull(noMethod);
|
||||||
|
|
||||||
final Method privateMethod = MethodUtil.getMethod(ReflectUtilTest.TestSubClass.class, "privateMethod");
|
final Method privateMethod = MethodUtil.getMethod(TestSubClass.class, "privateMethod");
|
||||||
Assertions.assertNotNull(privateMethod);
|
Assertions.assertNotNull(privateMethod);
|
||||||
final Method publicMethod = MethodUtil.getMethod(ReflectUtilTest.TestSubClass.class, "publicMethod");
|
final Method publicMethod = MethodUtil.getMethod(TestSubClass.class, "publicMethod");
|
||||||
Assertions.assertNotNull(publicMethod);
|
Assertions.assertNotNull(publicMethod);
|
||||||
|
|
||||||
final Method publicSubMethod = MethodUtil.getMethod(ReflectUtilTest.TestSubClass.class, "publicSubMethod");
|
final Method publicSubMethod = MethodUtil.getMethod(TestSubClass.class, "publicSubMethod");
|
||||||
Assertions.assertNotNull(publicSubMethod);
|
Assertions.assertNotNull(publicSubMethod);
|
||||||
final Method privateSubMethod = MethodUtil.getMethod(ReflectUtilTest.TestSubClass.class, "privateSubMethod");
|
final Method privateSubMethod = MethodUtil.getMethod(TestSubClass.class, "privateSubMethod");
|
||||||
Assertions.assertNotNull(privateSubMethod);
|
Assertions.assertNotNull(privateSubMethod);
|
||||||
}
|
}
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user