This commit is contained in:
Looly 2024-05-15 17:31:33 +08:00
parent b921895917
commit 56c076d2f6
8 changed files with 103 additions and 342 deletions

View File

@ -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;

View File

@ -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);
} }
/** /**

View File

@ -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());
} }

View File

@ -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);
} }

View File

@ -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();
}
} }
} }

View File

@ -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() {

View File

@ -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 childparentgrandparent
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 {
}
}

View File

@ -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方法
// 因此此处得到包括TestInterface1TestInterface2TestInterface3中一共4个方法 // 因此此处得到包括TestInterface1TestInterface2TestInterface3中一共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);
} }