mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-05-09 23:51:34 +08:00
add method
This commit is contained in:
parent
a0251bba01
commit
eb5fbbb11e
@ -62,6 +62,7 @@ import java.util.function.Supplier;
|
|||||||
* @since 5.7.21
|
* @since 5.7.21
|
||||||
*/
|
*/
|
||||||
public class GenericBuilder<T> implements Builder<T> {
|
public class GenericBuilder<T> implements Builder<T> {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 实例化器
|
* 实例化器
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
package cn.hutool.core.lang.func;
|
package cn.hutool.core.lang.func;
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.lang.invoke.SerializedLambda;
|
|
||||||
|
|
||||||
import cn.hutool.core.bean.BeanUtil;
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
import cn.hutool.core.lang.SimpleCache;
|
import cn.hutool.core.lang.SimpleCache;
|
||||||
import cn.hutool.core.util.ClassUtil;
|
import cn.hutool.core.util.ClassUtil;
|
||||||
import cn.hutool.core.util.ReflectUtil;
|
import cn.hutool.core.util.ReflectUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.lang.invoke.MethodHandleInfo;
|
||||||
|
import java.lang.invoke.SerializedLambda;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lambda相关工具类
|
* Lambda相关工具类
|
||||||
*
|
*
|
||||||
@ -25,7 +26,7 @@ public class LambdaUtil {
|
|||||||
* <pre>{@code
|
* <pre>{@code
|
||||||
* @Data
|
* @Data
|
||||||
* @EqualsAndHashCode(callSuper = true)
|
* @EqualsAndHashCode(callSuper = true)
|
||||||
* static class MyTeacher extends Entity<MyTeacher> {
|
* static class MyTeacher extends Entity<MyTeacher> {
|
||||||
*
|
*
|
||||||
* public String age;
|
* public String age;
|
||||||
*
|
*
|
||||||
@ -64,9 +65,10 @@ public class LambdaUtil {
|
|||||||
* @return lambda实现类
|
* @return lambda实现类
|
||||||
* @throws IllegalArgumentException 如果是不支持的方法引用,抛出该异常,见{@link LambdaUtil#checkLambdaTypeCanGetClass}
|
* @throws IllegalArgumentException 如果是不支持的方法引用,抛出该异常,见{@link LambdaUtil#checkLambdaTypeCanGetClass}
|
||||||
* @since 5.8.0
|
* @since 5.8.0
|
||||||
|
* @author VampireAchao
|
||||||
*/
|
*/
|
||||||
public static <R> Class<R> getRealClass(Func0<?> func) {
|
public static <R> Class<R> getRealClass(Func0<?> func) {
|
||||||
SerializedLambda lambda = resolve(func);
|
final SerializedLambda lambda = resolve(func);
|
||||||
checkLambdaTypeCanGetClass(lambda.getImplMethodKind());
|
checkLambdaTypeCanGetClass(lambda.getImplMethodKind());
|
||||||
return ClassUtil.loadClass(lambda.getImplClass());
|
return ClassUtil.loadClass(lambda.getImplClass());
|
||||||
}
|
}
|
||||||
@ -125,7 +127,7 @@ public class LambdaUtil {
|
|||||||
* <pre>{@code
|
* <pre>{@code
|
||||||
* @Data
|
* @Data
|
||||||
* @EqualsAndHashCode(callSuper = true)
|
* @EqualsAndHashCode(callSuper = true)
|
||||||
* static class MyTeacher extends Entity<MyTeacher> {
|
* static class MyTeacher extends Entity<MyTeacher> {
|
||||||
*
|
*
|
||||||
* public String age;
|
* public String age;
|
||||||
*
|
*
|
||||||
@ -152,27 +154,15 @@ public class LambdaUtil {
|
|||||||
* @return lambda实现类
|
* @return lambda实现类
|
||||||
* @throws IllegalArgumentException 如果是不支持的方法引用,抛出该异常,见{@link LambdaUtil#checkLambdaTypeCanGetClass}
|
* @throws IllegalArgumentException 如果是不支持的方法引用,抛出该异常,见{@link LambdaUtil#checkLambdaTypeCanGetClass}
|
||||||
* @since 5.8.0
|
* @since 5.8.0
|
||||||
|
* @author VampireAchao
|
||||||
*/
|
*/
|
||||||
public static <P, R> Class<P> getRealClass(Func1<P, R> func) {
|
public static <P, R> Class<P> getRealClass(Func1<P, R> func) {
|
||||||
SerializedLambda lambda = resolve(func);
|
final SerializedLambda lambda = resolve(func);
|
||||||
checkLambdaTypeCanGetClass(lambda.getImplMethodKind());
|
checkLambdaTypeCanGetClass(lambda.getImplMethodKind());
|
||||||
String instantiatedMethodType = lambda.getInstantiatedMethodType();
|
final String instantiatedMethodType = lambda.getInstantiatedMethodType();
|
||||||
return ClassUtil.loadClass(StrUtil.sub(instantiatedMethodType, 2, StrUtil.indexOf(instantiatedMethodType, ';')));
|
return ClassUtil.loadClass(StrUtil.sub(instantiatedMethodType, 2, StrUtil.indexOf(instantiatedMethodType, ';')));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 检查是否为支持的类型
|
|
||||||
*
|
|
||||||
* @param implMethodKind 支持的lambda类型
|
|
||||||
* @throws IllegalArgumentException 如果是不支持的方法引用,抛出该异常
|
|
||||||
*/
|
|
||||||
private static void checkLambdaTypeCanGetClass(int implMethodKind) {
|
|
||||||
if (implMethodKind != LambdaKindEnum.REF_invokeVirtual.ordinal() &&
|
|
||||||
implMethodKind != LambdaKindEnum.REF_invokeStatic.ordinal()) {
|
|
||||||
throw new IllegalArgumentException("该lambda不是合适的方法引用");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取lambda表达式Getter或Setter函数(方法)对应的字段名称,规则如下:
|
* 获取lambda表达式Getter或Setter函数(方法)对应的字段名称,规则如下:
|
||||||
* <ul>
|
* <ul>
|
||||||
@ -211,9 +201,28 @@ public class LambdaUtil {
|
|||||||
return BeanUtil.getFieldName(getMethodName(func));
|
return BeanUtil.getFieldName(getMethodName(func));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//region Private methods
|
||||||
|
/**
|
||||||
|
* 检查是否为支持的类型
|
||||||
|
*
|
||||||
|
* @param implMethodKind 支持的lambda类型
|
||||||
|
* @throws IllegalArgumentException 如果是不支持的方法引用,抛出该异常
|
||||||
|
*/
|
||||||
|
private static void checkLambdaTypeCanGetClass(int implMethodKind) {
|
||||||
|
if (implMethodKind != MethodHandleInfo.REF_invokeVirtual &&
|
||||||
|
implMethodKind != MethodHandleInfo.REF_invokeStatic) {
|
||||||
|
throw new IllegalArgumentException("该lambda不是合适的方法引用");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 解析lambda表达式,加了缓存。
|
* 解析lambda表达式,加了缓存。
|
||||||
* 该缓存可能会在任意不定的时间被清除
|
* 该缓存可能会在任意不定的时间被清除。
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 通过反射调用实现序列化接口函数对象的writeReplace方法,从而拿到{@link SerializedLambda}<br>
|
||||||
|
* 该对象中包含了lambda表达式的所有信息。
|
||||||
|
* </p>
|
||||||
*
|
*
|
||||||
* @param func 需要解析的 lambda 对象
|
* @param func 需要解析的 lambda 对象
|
||||||
* @return 返回解析后的结果
|
* @return 返回解析后的结果
|
||||||
@ -221,20 +230,5 @@ public class LambdaUtil {
|
|||||||
private static SerializedLambda _resolve(Serializable func) {
|
private static SerializedLambda _resolve(Serializable func) {
|
||||||
return cache.get(func.getClass().getName(), () -> ReflectUtil.invoke(func, "writeReplace"));
|
return cache.get(func.getClass().getName(), () -> ReflectUtil.invoke(func, "writeReplace"));
|
||||||
}
|
}
|
||||||
|
//endregion
|
||||||
/**
|
|
||||||
* Lambda类型枚举
|
|
||||||
*/
|
|
||||||
public enum LambdaKindEnum {
|
|
||||||
REF_NONE,
|
|
||||||
REF_getField,
|
|
||||||
REF_getStatic,
|
|
||||||
REF_putField,
|
|
||||||
REF_putStatic,
|
|
||||||
REF_invokeVirtual,
|
|
||||||
REF_invokeStatic,
|
|
||||||
REF_invokeSpecial,
|
|
||||||
REF_newInvokeSpecial,
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,8 @@ import lombok.AllArgsConstructor;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
import java.lang.invoke.MethodHandleInfo;
|
||||||
|
|
||||||
public class LambdaUtilTest {
|
public class LambdaUtilTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -24,19 +26,19 @@ public class LambdaUtilTest {
|
|||||||
@Test
|
@Test
|
||||||
public void resolveTest() {
|
public void resolveTest() {
|
||||||
// 引用构造函数
|
// 引用构造函数
|
||||||
Assert.assertEquals(LambdaUtil.LambdaKindEnum.REF_newInvokeSpecial.ordinal(),
|
Assert.assertEquals(MethodHandleInfo.REF_newInvokeSpecial,
|
||||||
LambdaUtil.resolve(MyTeacher::new).getImplMethodKind());
|
LambdaUtil.resolve(MyTeacher::new).getImplMethodKind());
|
||||||
// 数组构造函数引用
|
// 数组构造函数引用
|
||||||
Assert.assertEquals(LambdaUtil.LambdaKindEnum.REF_invokeStatic.ordinal(),
|
Assert.assertEquals(MethodHandleInfo.REF_invokeStatic,
|
||||||
LambdaUtil.resolve(MyTeacher[]::new).getImplMethodKind());
|
LambdaUtil.resolve(MyTeacher[]::new).getImplMethodKind());
|
||||||
// 引用静态方法
|
// 引用静态方法
|
||||||
Assert.assertEquals(LambdaUtil.LambdaKindEnum.REF_invokeStatic.ordinal(),
|
Assert.assertEquals(MethodHandleInfo.REF_invokeStatic,
|
||||||
LambdaUtil.resolve(MyTeacher::takeAge).getImplMethodKind());
|
LambdaUtil.resolve(MyTeacher::takeAge).getImplMethodKind());
|
||||||
// 引用特定对象的实例方法
|
// 引用特定对象的实例方法
|
||||||
Assert.assertEquals(LambdaUtil.LambdaKindEnum.REF_invokeVirtual.ordinal(),
|
Assert.assertEquals(MethodHandleInfo.REF_invokeVirtual,
|
||||||
LambdaUtil.resolve(new MyTeacher()::getAge).getImplMethodKind());
|
LambdaUtil.resolve(new MyTeacher()::getAge).getImplMethodKind());
|
||||||
// 引用特定类型的任意对象的实例方法
|
// 引用特定类型的任意对象的实例方法
|
||||||
Assert.assertEquals(LambdaUtil.LambdaKindEnum.REF_invokeVirtual.ordinal(),
|
Assert.assertEquals(MethodHandleInfo.REF_invokeVirtual,
|
||||||
LambdaUtil.resolve(MyTeacher::getAge).getImplMethodKind());
|
LambdaUtil.resolve(MyTeacher::getAge).getImplMethodKind());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,8 +49,8 @@ public class LambdaUtilTest {
|
|||||||
Class<MyTeacher> functionClass = LambdaUtil.getRealClass(MyTeacher::getAge);
|
Class<MyTeacher> functionClass = LambdaUtil.getRealClass(MyTeacher::getAge);
|
||||||
Assert.assertEquals(MyTeacher.class, functionClass);
|
Assert.assertEquals(MyTeacher.class, functionClass);
|
||||||
// 枚举测试,不会导致类型擦除
|
// 枚举测试,不会导致类型擦除
|
||||||
Class<LambdaUtil.LambdaKindEnum> enumFunctionClass = LambdaUtil.getRealClass(LambdaUtil.LambdaKindEnum::ordinal);
|
Class<LambdaKindEnum> enumFunctionClass = LambdaUtil.getRealClass(LambdaKindEnum::ordinal);
|
||||||
Assert.assertEquals(LambdaUtil.LambdaKindEnum.class, enumFunctionClass);
|
Assert.assertEquals(LambdaKindEnum.class, enumFunctionClass);
|
||||||
// 调用父类方法,能获取到正确的子类类型
|
// 调用父类方法,能获取到正确的子类类型
|
||||||
Class<MyTeacher> superFunctionClass = LambdaUtil.getRealClass(MyTeacher::getId);
|
Class<MyTeacher> superFunctionClass = LambdaUtil.getRealClass(MyTeacher::getId);
|
||||||
Assert.assertEquals(MyTeacher.class, superFunctionClass);
|
Assert.assertEquals(MyTeacher.class, superFunctionClass);
|
||||||
@ -58,7 +60,7 @@ public class LambdaUtilTest {
|
|||||||
Class<MyTeacher> supplierClass = LambdaUtil.getRealClass(myTeacher::getAge);
|
Class<MyTeacher> supplierClass = LambdaUtil.getRealClass(myTeacher::getAge);
|
||||||
Assert.assertEquals(MyTeacher.class, supplierClass);
|
Assert.assertEquals(MyTeacher.class, supplierClass);
|
||||||
// 枚举测试,只能获取到枚举类型
|
// 枚举测试,只能获取到枚举类型
|
||||||
Class<Enum<?>> enumSupplierClass = LambdaUtil.getRealClass(LambdaUtil.LambdaKindEnum.REF_NONE::ordinal);
|
Class<Enum<?>> enumSupplierClass = LambdaUtil.getRealClass(LambdaKindEnum.REF_NONE::ordinal);
|
||||||
Assert.assertEquals(Enum.class, enumSupplierClass);
|
Assert.assertEquals(Enum.class, enumSupplierClass);
|
||||||
// 调用父类方法,只能获取到父类类型
|
// 调用父类方法,只能获取到父类类型
|
||||||
Class<Entity<?>> superSupplierClass = LambdaUtil.getRealClass(myTeacher::getId);
|
Class<Entity<?>> superSupplierClass = LambdaUtil.getRealClass(myTeacher::getId);
|
||||||
@ -116,4 +118,19 @@ public class LambdaUtilTest {
|
|||||||
|
|
||||||
public String age;
|
public String age;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 测试Lambda类型枚举
|
||||||
|
*/
|
||||||
|
enum LambdaKindEnum {
|
||||||
|
REF_NONE,
|
||||||
|
REF_getField,
|
||||||
|
REF_getStatic,
|
||||||
|
REF_putField,
|
||||||
|
REF_putStatic,
|
||||||
|
REF_invokeVirtual,
|
||||||
|
REF_invokeStatic,
|
||||||
|
REF_invokeSpecial,
|
||||||
|
REF_newInvokeSpecial,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user