add method

This commit is contained in:
Looly 2022-03-26 00:15:12 +08:00
parent a0251bba01
commit eb5fbbb11e
3 changed files with 58 additions and 46 deletions

View File

@ -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;
/** /**
* 实例化器 * 实例化器

View File

@ -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&lt;MyTeacher&gt; {
* *
* 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&lt;MyTeacher&gt; {
* *
* 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,
}
} }

View File

@ -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,
}
} }