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,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方法
// 因此此处得到包括TestInterface1、TestInterface2、TestInterface3中一共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方法
// 因此此处得到包括TestInterface1、TestInterface2、TestInterface3中一共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);