From eb5fbbb11e014fda8ae44c85354a57457b456ec9 Mon Sep 17 00:00:00 2001 From: Looly Date: Sat, 26 Mar 2022 00:15:12 +0800 Subject: [PATCH] add method --- .../hutool/core/builder/GenericBuilder.java | 1 + .../cn/hutool/core/lang/func/LambdaUtil.java | 70 +++++++++---------- .../hutool/core/lang/func/LambdaUtilTest.java | 33 ++++++--- 3 files changed, 58 insertions(+), 46 deletions(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/builder/GenericBuilder.java b/hutool-core/src/main/java/cn/hutool/core/builder/GenericBuilder.java index 5d9f0e1f3..817df55ad 100644 --- a/hutool-core/src/main/java/cn/hutool/core/builder/GenericBuilder.java +++ b/hutool-core/src/main/java/cn/hutool/core/builder/GenericBuilder.java @@ -62,6 +62,7 @@ import java.util.function.Supplier; * @since 5.7.21 */ public class GenericBuilder implements Builder { + private static final long serialVersionUID = 1L; /** * 实例化器 diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/func/LambdaUtil.java b/hutool-core/src/main/java/cn/hutool/core/lang/func/LambdaUtil.java index fec85ba75..25d28aacb 100644 --- a/hutool-core/src/main/java/cn/hutool/core/lang/func/LambdaUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/func/LambdaUtil.java @@ -1,14 +1,15 @@ 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.lang.SimpleCache; import cn.hutool.core.util.ClassUtil; import cn.hutool.core.util.ReflectUtil; import cn.hutool.core.util.StrUtil; +import java.io.Serializable; +import java.lang.invoke.MethodHandleInfo; +import java.lang.invoke.SerializedLambda; + /** * Lambda相关工具类 * @@ -25,7 +26,7 @@ public class LambdaUtil { *
{@code
 	 * @Data
 	 * @EqualsAndHashCode(callSuper = true)
-	 * static class MyTeacher extends Entity {
+	 * static class MyTeacher extends Entity<MyTeacher> {
 	 *
 	 * 	public String age;
 	 *
@@ -64,9 +65,10 @@ public class LambdaUtil {
 	 * @return lambda实现类
 	 * @throws IllegalArgumentException 如果是不支持的方法引用,抛出该异常,见{@link LambdaUtil#checkLambdaTypeCanGetClass}
 	 * @since 5.8.0
+	 * @author VampireAchao
 	 */
 	public static  Class getRealClass(Func0 func) {
-		SerializedLambda lambda = resolve(func);
+		final SerializedLambda lambda = resolve(func);
 		checkLambdaTypeCanGetClass(lambda.getImplMethodKind());
 		return ClassUtil.loadClass(lambda.getImplClass());
 	}
@@ -125,7 +127,7 @@ public class LambdaUtil {
 	 * 
{@code
 	 * @Data
 	 * @EqualsAndHashCode(callSuper = true)
-	 * static class MyTeacher extends Entity {
+	 * static class MyTeacher extends Entity<MyTeacher> {
 	 *
 	 * 	public String age;
 	 *
@@ -152,27 +154,15 @@ public class LambdaUtil {
 	 * @return lambda实现类
 	 * @throws IllegalArgumentException 如果是不支持的方法引用,抛出该异常,见{@link LambdaUtil#checkLambdaTypeCanGetClass}
 	 * @since 5.8.0
+	 * @author VampireAchao
 	 */
 	public static  Class

getRealClass(Func1 func) { - SerializedLambda lambda = resolve(func); + final SerializedLambda lambda = resolve(func); checkLambdaTypeCanGetClass(lambda.getImplMethodKind()); - String instantiatedMethodType = lambda.getInstantiatedMethodType(); + final String instantiatedMethodType = lambda.getInstantiatedMethodType(); 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函数(方法)对应的字段名称,规则如下: *

    @@ -211,9 +201,28 @@ public class LambdaUtil { 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表达式,加了缓存。 - * 该缓存可能会在任意不定的时间被清除 + * 该缓存可能会在任意不定的时间被清除。 + * + *

    + * 通过反射调用实现序列化接口函数对象的writeReplace方法,从而拿到{@link SerializedLambda}
    + * 该对象中包含了lambda表达式的所有信息。 + *

    * * @param func 需要解析的 lambda 对象 * @return 返回解析后的结果 @@ -221,20 +230,5 @@ public class LambdaUtil { private static SerializedLambda _resolve(Serializable func) { return cache.get(func.getClass().getName(), () -> ReflectUtil.invoke(func, "writeReplace")); } - - /** - * Lambda类型枚举 - */ - public enum LambdaKindEnum { - REF_NONE, - REF_getField, - REF_getStatic, - REF_putField, - REF_putStatic, - REF_invokeVirtual, - REF_invokeStatic, - REF_invokeSpecial, - REF_newInvokeSpecial, - } - + //endregion } diff --git a/hutool-core/src/test/java/cn/hutool/core/lang/func/LambdaUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/lang/func/LambdaUtilTest.java index 2facb9336..e13ef6fa8 100644 --- a/hutool-core/src/test/java/cn/hutool/core/lang/func/LambdaUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/lang/func/LambdaUtilTest.java @@ -7,6 +7,8 @@ import lombok.AllArgsConstructor; import lombok.Data; import lombok.EqualsAndHashCode; +import java.lang.invoke.MethodHandleInfo; + public class LambdaUtilTest { @Test @@ -24,19 +26,19 @@ public class LambdaUtilTest { @Test public void resolveTest() { // 引用构造函数 - Assert.assertEquals(LambdaUtil.LambdaKindEnum.REF_newInvokeSpecial.ordinal(), + Assert.assertEquals(MethodHandleInfo.REF_newInvokeSpecial, LambdaUtil.resolve(MyTeacher::new).getImplMethodKind()); // 数组构造函数引用 - Assert.assertEquals(LambdaUtil.LambdaKindEnum.REF_invokeStatic.ordinal(), + Assert.assertEquals(MethodHandleInfo.REF_invokeStatic, LambdaUtil.resolve(MyTeacher[]::new).getImplMethodKind()); // 引用静态方法 - Assert.assertEquals(LambdaUtil.LambdaKindEnum.REF_invokeStatic.ordinal(), + Assert.assertEquals(MethodHandleInfo.REF_invokeStatic, LambdaUtil.resolve(MyTeacher::takeAge).getImplMethodKind()); // 引用特定对象的实例方法 - Assert.assertEquals(LambdaUtil.LambdaKindEnum.REF_invokeVirtual.ordinal(), + Assert.assertEquals(MethodHandleInfo.REF_invokeVirtual, LambdaUtil.resolve(new MyTeacher()::getAge).getImplMethodKind()); // 引用特定类型的任意对象的实例方法 - Assert.assertEquals(LambdaUtil.LambdaKindEnum.REF_invokeVirtual.ordinal(), + Assert.assertEquals(MethodHandleInfo.REF_invokeVirtual, LambdaUtil.resolve(MyTeacher::getAge).getImplMethodKind()); } @@ -47,8 +49,8 @@ public class LambdaUtilTest { Class functionClass = LambdaUtil.getRealClass(MyTeacher::getAge); Assert.assertEquals(MyTeacher.class, functionClass); // 枚举测试,不会导致类型擦除 - Class enumFunctionClass = LambdaUtil.getRealClass(LambdaUtil.LambdaKindEnum::ordinal); - Assert.assertEquals(LambdaUtil.LambdaKindEnum.class, enumFunctionClass); + Class enumFunctionClass = LambdaUtil.getRealClass(LambdaKindEnum::ordinal); + Assert.assertEquals(LambdaKindEnum.class, enumFunctionClass); // 调用父类方法,能获取到正确的子类类型 Class superFunctionClass = LambdaUtil.getRealClass(MyTeacher::getId); Assert.assertEquals(MyTeacher.class, superFunctionClass); @@ -58,7 +60,7 @@ public class LambdaUtilTest { Class supplierClass = LambdaUtil.getRealClass(myTeacher::getAge); Assert.assertEquals(MyTeacher.class, supplierClass); // 枚举测试,只能获取到枚举类型 - Class> enumSupplierClass = LambdaUtil.getRealClass(LambdaUtil.LambdaKindEnum.REF_NONE::ordinal); + Class> enumSupplierClass = LambdaUtil.getRealClass(LambdaKindEnum.REF_NONE::ordinal); Assert.assertEquals(Enum.class, enumSupplierClass); // 调用父类方法,只能获取到父类类型 Class> superSupplierClass = LambdaUtil.getRealClass(myTeacher::getId); @@ -116,4 +118,19 @@ public class LambdaUtilTest { public String age; } + + /** + * 测试Lambda类型枚举 + */ + enum LambdaKindEnum { + REF_NONE, + REF_getField, + REF_getStatic, + REF_putField, + REF_putStatic, + REF_invokeVirtual, + REF_invokeStatic, + REF_invokeSpecial, + REF_newInvokeSpecial, + } }