获取lambda

2022-12-18

java

处世让一步为高,退步即进步的张本;待人宽一分是福利人利己的根基。——洪自诚

昨天说了获取lambda代理

今天获取实际lambda对象

重要的是这个函数java.lang.invoke.LambdaMetafactory#metafactory以及altMetafactory

我们在昨天的基础上,进行获取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Test
@SneakyThrows
void testVirtual() {
final MethodHandle virtual = MethodHandles.lookup().findVirtual(LambdaExecutable.class, "getName", MethodType.methodType(String.class));
final SerFunc<LambdaExecutable, String> proxy = MethodHandleProxies.asInterfaceInstance(SerFunc.class, virtual);
InvocationHandler handler = Proxy.getInvocationHandler(proxy);
MethodHandle methodHandle = ReflectHelper.getFieldValue(handler, "val$target");
final CallSite callSite = LambdaMetafactory.altMetafactory(
MethodHandles.lookup(),
"apply",
MethodType.methodType(SerFunc.class),
MethodType.methodType(Object.class, Object.class),
methodHandle,
MethodType.methodType(String.class, LambdaExecutable.class),
LambdaMetafactory.FLAG_SERIALIZABLE
);
final MethodHandle target = callSite.getTarget();
final SerFunc<LambdaExecutable, String> invoke = (SerFunc<LambdaExecutable, String>) target.invoke();
final LambdaExecutable executable = new LambdaExecutable();
executable.setName("test");
Assertions.assertEquals("test", invoke.apply(executable));
Assertions.assertEquals("getName", LambdaHelper.resolve(invoke).getName());
}

进一步封装后:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public static <T> T revert(Class<T> clazz, Executable executable) {
final Method funcMethod = Steam.of(clazz.getMethods()).findFirst(method -> Modifier.isAbstract(method.getModifiers()))
.orElseThrow(() -> new UtilException("not a functional interface"));
final MethodHandle implMethod;
final MethodType instantiatedMethodType;
if (executable instanceof Method) {
final Method method = (Method) executable;
implMethod = ((SerSupp<MethodHandle>) () -> MethodHandles.lookup().unreflect(method)).get();
instantiatedMethodType = MethodType.methodType(method.getReturnType(), method.getDeclaringClass(), method.getParameterTypes());
} else {
final Constructor<?> constructor = (Constructor<?>) executable;
implMethod = ((SerSupp<MethodHandle>) () -> MethodHandles.lookup().unreflectConstructor(constructor)).get();
instantiatedMethodType = MethodType.methodType(constructor.getDeclaringClass(), constructor.getParameterTypes());
}
final CallSite callSite = ((SerSupp<CallSite>) () ->
Serializable.class.isAssignableFrom(clazz) ?
LambdaMetafactory.altMetafactory(
MethodHandles.lookup(),
funcMethod.getName(),
MethodType.methodType(clazz),
MethodType.methodType(funcMethod.getReturnType(), funcMethod.getParameterTypes()),
implMethod,
instantiatedMethodType,
LambdaMetafactory.FLAG_SERIALIZABLE
) :
LambdaMetafactory.metafactory(
MethodHandles.lookup(),
funcMethod.getName(),
MethodType.methodType(clazz),
MethodType.methodType(funcMethod.getReturnType(), funcMethod.getParameterTypes()),
implMethod,
instantiatedMethodType
)
).get();
final MethodHandle target = callSite.getTarget();
return ((SerSupp<T>) () -> SerFunc.<Object, T>cast().apply(target.invoke())).get();
}

使用方式:

1
2
3
4
5
6
7
8
9
10
@Test
void testRevert() {
final LambdaExecutable getName = LambdaHelper.<SerFunc<LambdaExecutable, String>>resolve(LambdaExecutable::getName);
final SerFunc<LambdaExecutable, String> revertedGetName = LambdaHelper.revert(SerFunc.class, getName.getExecutable());
Assertions.assertEquals(revertedGetName.apply(getName), getName.getName());

final LambdaExecutable constructor = LambdaHelper.<SerSupp<LambdaExecutable>>resolve(LambdaExecutable::new);
final SerSupp<LambdaExecutable> revertedConstructor = LambdaHelper.revert(SerSupp.class, constructor.getExecutable());
Assertions.assertEquals(LambdaExecutable.class, revertedConstructor.get().getClass());
}

源码地址:https://gitee.com/VampireAchao/stream-query