mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-04-19 03:01:48 +08:00
add method
This commit is contained in:
parent
05495ba8ed
commit
520b503065
@ -1,9 +1,12 @@
|
|||||||
package cn.hutool.core.lang.reflect;
|
package cn.hutool.core.lang.reflect;
|
||||||
|
|
||||||
import cn.hutool.core.exceptions.UtilException;
|
import cn.hutool.core.exceptions.UtilException;
|
||||||
|
import cn.hutool.core.lang.Assert;
|
||||||
|
import cn.hutool.core.util.ReflectUtil;
|
||||||
|
|
||||||
import java.lang.invoke.MethodHandle;
|
import java.lang.invoke.MethodHandle;
|
||||||
import java.lang.invoke.MethodHandles;
|
import java.lang.invoke.MethodHandles;
|
||||||
|
import java.lang.invoke.MethodType;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -29,6 +32,53 @@ public class MethodHandleUtil {
|
|||||||
return LookupFactory.lookup(callerClass);
|
return LookupFactory.lookup(callerClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查找指定方法的方法句柄<br>
|
||||||
|
* 此方法只会查找:
|
||||||
|
* <ul>
|
||||||
|
* <li>当前类的方法(包括构造方法和private方法)</li>
|
||||||
|
* <li>父类的方法(包括构造方法和private方法)</li>
|
||||||
|
* <li>当前类的static方法</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* @param callerClass 方法所在类或接口
|
||||||
|
* @param name 方法名称
|
||||||
|
* @param type 返回类型和参数类型
|
||||||
|
* @return 方法句柄 {@link MethodHandle},{@code null}表示未找到方法
|
||||||
|
*/
|
||||||
|
public static MethodHandle findMethod(Class<?> callerClass, String name, MethodType type){
|
||||||
|
MethodHandle handle = null;
|
||||||
|
|
||||||
|
final MethodHandles.Lookup lookup = lookup(callerClass);
|
||||||
|
try {
|
||||||
|
handle = lookup.findVirtual(callerClass, name, type);
|
||||||
|
} catch (IllegalAccessException | NoSuchMethodException ignore) {
|
||||||
|
//ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
// static方法
|
||||||
|
if(null == handle){
|
||||||
|
try {
|
||||||
|
handle = lookup.findStatic(callerClass, name, type);
|
||||||
|
} catch (IllegalAccessException | NoSuchMethodException ignore) {
|
||||||
|
//ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 特殊方法,包括构造方法、私有方法等
|
||||||
|
if(null == handle){
|
||||||
|
try {
|
||||||
|
handle = lookup.findSpecial(callerClass, name, type, callerClass);
|
||||||
|
} catch (NoSuchMethodException ignore) {
|
||||||
|
//ignore
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
throw new UtilException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 执行Interface中的default方法<br>
|
* 执行Interface中的default方法<br>
|
||||||
*
|
*
|
||||||
@ -45,18 +95,50 @@ public class MethodHandleUtil {
|
|||||||
* MethodHandleUtil::invokeDefault);
|
* MethodHandleUtil::invokeDefault);
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
* @param o 接口的子对象或代理对象
|
* @param obj 接口的子对象或代理对象
|
||||||
|
* @param methodName 方法名称
|
||||||
|
* @param args 参数
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public static <T> T invoke(Object obj, String methodName, Object... args) {
|
||||||
|
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);
|
||||||
|
if (null == method) {
|
||||||
|
throw new UtilException("No such method: [{}] from [{}]", methodName, obj.getClass());
|
||||||
|
}
|
||||||
|
return invoke(obj, method, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行Interface中的default方法<br>
|
||||||
|
*
|
||||||
|
* <pre class="code">
|
||||||
|
* interface Duck {
|
||||||
|
* default String quack() {
|
||||||
|
* return "Quack";
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* Duck duck = (Duck) Proxy.newProxyInstance(
|
||||||
|
* ClassLoaderUtil.getClassLoader(),
|
||||||
|
* new Class[] { Duck.class },
|
||||||
|
* MethodHandleUtil::invokeDefault);
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @param obj 接口的子对象或代理对象
|
||||||
* @param method 方法
|
* @param method 方法
|
||||||
* @param args 参数
|
* @param args 参数
|
||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public static <T> T invoke(Object o, Method method, Object... args) {
|
public static <T> T invoke(Object obj, Method method, Object... args) {
|
||||||
final Class<?> declaringClass = method.getDeclaringClass();
|
final Class<?> declaringClass = method.getDeclaringClass();
|
||||||
try {
|
try {
|
||||||
return (T) lookup(declaringClass)
|
return (T) lookup(declaringClass)
|
||||||
.unreflectSpecial(method, declaringClass)
|
.unreflectSpecial(method, declaringClass)
|
||||||
.bindTo(o)
|
.bindTo(obj)
|
||||||
.invokeWithArguments(args);
|
.invokeWithArguments(args);
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
throw new UtilException(e);
|
throw new UtilException(e);
|
||||||
|
@ -944,9 +944,12 @@ public class ReflectUtil {
|
|||||||
* @since 3.1.2
|
* @since 3.1.2
|
||||||
*/
|
*/
|
||||||
public static <T> T invoke(Object obj, String methodName, Object... args) throws UtilException {
|
public static <T> T invoke(Object obj, String methodName, 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);
|
final Method method = getMethodOfObj(obj, methodName, args);
|
||||||
if (null == method) {
|
if (null == method) {
|
||||||
throw new UtilException(StrUtil.format("No such method: [{}]", methodName));
|
throw new UtilException("No such method: [{}] from [{}]", methodName, obj.getClass());
|
||||||
}
|
}
|
||||||
return invoke(obj, method, args);
|
return invoke(obj, method, args);
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,8 @@ import cn.hutool.core.util.ReflectUtil;
|
|||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.lang.invoke.MethodHandle;
|
||||||
|
import java.lang.invoke.MethodType;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Proxy;
|
import java.lang.reflect.Proxy;
|
||||||
|
|
||||||
@ -39,6 +41,16 @@ public class MethodHandleUtilTest {
|
|||||||
Assert.assertEquals("Quack", duck.quack());
|
Assert.assertEquals("Quack", duck.quack());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void invokeStaticTest(){
|
||||||
|
Duck duck = (Duck) Proxy.newProxyInstance(
|
||||||
|
ClassLoaderUtil.getClassLoader(),
|
||||||
|
new Class[] { Duck.class },
|
||||||
|
ReflectUtil::invoke);
|
||||||
|
|
||||||
|
Assert.assertEquals("Quack", duck.quack());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void invokeTest(){
|
public void invokeTest(){
|
||||||
// 测试执行普通方法
|
// 测试执行普通方法
|
||||||
@ -47,15 +59,88 @@ public class MethodHandleUtilTest {
|
|||||||
Assert.assertEquals(36, size);
|
Assert.assertEquals(36, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void findMethodTest() throws Throwable {
|
||||||
|
MethodHandle handle = MethodHandleUtil.findMethod(Duck.class, "quack",
|
||||||
|
MethodType.methodType(String.class));
|
||||||
|
Assert.assertNotNull(handle);
|
||||||
|
// 对象方法自行需要绑定对象或者传入对象参数
|
||||||
|
String invoke = (String) handle.invoke(new BigDuck());
|
||||||
|
Assert.assertEquals("Quack", invoke);
|
||||||
|
|
||||||
|
// 对象的方法获取
|
||||||
|
handle = MethodHandleUtil.findMethod(BigDuck.class, "getSize",
|
||||||
|
MethodType.methodType(int.class));
|
||||||
|
Assert.assertNotNull(handle);
|
||||||
|
int invokeInt = (int) handle.invoke(new BigDuck());
|
||||||
|
Assert.assertEquals(36, invokeInt);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void findStaticMethodTest() throws Throwable {
|
||||||
|
final MethodHandle handle = MethodHandleUtil.findMethod(Duck.class, "getDuck",
|
||||||
|
MethodType.methodType(String.class, int.class));
|
||||||
|
Assert.assertNotNull(handle);
|
||||||
|
|
||||||
|
// static 方法执行不需要绑定或者传入对象,直接传入参数即可
|
||||||
|
final String invoke = (String) handle.invoke(12);
|
||||||
|
Assert.assertEquals("Duck 12", invoke);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void findPrivateMethodTest() throws Throwable {
|
||||||
|
final MethodHandle handle = MethodHandleUtil.findMethod(BigDuck.class, "getPrivateValue",
|
||||||
|
MethodType.methodType(String.class));
|
||||||
|
Assert.assertNotNull(handle);
|
||||||
|
|
||||||
|
final String invoke = (String) handle.invoke(new BigDuck());
|
||||||
|
Assert.assertEquals("private value", invoke);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void findSuperMethodTest() throws Throwable {
|
||||||
|
// 查找父类的方法
|
||||||
|
final MethodHandle handle = MethodHandleUtil.findMethod(BigDuck.class, "quack",
|
||||||
|
MethodType.methodType(String.class));
|
||||||
|
Assert.assertNotNull(handle);
|
||||||
|
|
||||||
|
final String invoke = (String) handle.invoke(new BigDuck());
|
||||||
|
Assert.assertEquals("Quack", invoke);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void findPrivateStaticMethodTest() throws Throwable {
|
||||||
|
final MethodHandle handle = MethodHandleUtil.findMethod(BigDuck.class, "getPrivateStaticValue",
|
||||||
|
MethodType.methodType(String.class));
|
||||||
|
Assert.assertNotNull(handle);
|
||||||
|
|
||||||
|
final String invoke = (String) handle.invoke();
|
||||||
|
Assert.assertEquals("private static value", invoke);
|
||||||
|
}
|
||||||
|
|
||||||
interface Duck {
|
interface Duck {
|
||||||
default String quack() {
|
default String quack() {
|
||||||
return "Quack";
|
return "Quack";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static String getDuck(int count){
|
||||||
|
return "Duck " + count;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static class BigDuck implements Duck{
|
static class BigDuck implements Duck{
|
||||||
public int getSize(){
|
public int getSize(){
|
||||||
return 36;
|
return 36;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private String getPrivateValue(){
|
||||||
|
return "private value";
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private static String getPrivateStaticValue(){
|
||||||
|
return "private static value";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user