我试图使用Java的LambdaMetaFactory动态实现一个通用的拉姆达Handler<RoutingContext>:
public class RoutingContext {
// ...
}
@FunctionalInterface
public interface Handler<X> {
public void handle(X arg);
}
public class HomeHandler extends Handler<RoutingContext> {
@Override
public void handle(RoutingContext ctx) {
// ...
}
}
Run Code Online (Sandbox Code Playgroud)
这是我的尝试LambdaMetaFactory:
try {
Class<?> homeHandlerClass = HomeHandler.class;
Method method = homeHandlerClass.getDeclaredMethod(
"handle", RoutingContext.class);
Lookup lookup = MethodHandles.lookup();
MethodHandle mh = lookup.unreflect(method);
MethodType factoryMethodType = MethodType.methodType(Handler.class);
MethodType functionMethodType = mh.type();
MethodHandle implementationMethodHandle = mh;
Handler<RoutingContext> lambda =
(Handler<RoutingContext>) LambdaMetafactory.metafactory(
lookup,
"handle", …Run Code Online (Sandbox Code Playgroud) 鉴于:
import java.lang.invoke.LambdaMetafactory;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.function.Function;
class Testcase
{
@FunctionalInterface
public interface MyBuilder1<R>
{
R apply(String message);
}
@FunctionalInterface
public interface MyBuilder2<R>
{
R apply(Object message);
}
public static void main(String[] args) throws Throwable
{
Class<?> clazz = IllegalArgumentException.class;
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle mh = lookup.findConstructor(clazz, MethodType.methodType(void.class, String.class));
MethodHandle myFunctionConstructor = LambdaMetafactory.metafactory(
lookup,
"apply",
MethodType.methodType(Function.class),
mh.type().erase(),
mh,
mh.type()
).getTarget();
MethodHandle myBuilderConstructor1 = LambdaMetafactory.metafactory(
lookup,
"apply",
MethodType.methodType(MyBuilder1.class),
mh.type().erase(),
mh,
mh.type()
).getTarget();
MethodHandle myBuilderConstructor2 = LambdaMetafactory.metafactory( …Run Code Online (Sandbox Code Playgroud) 我有这段代码可以正常工作:
Method getterMethod = Person.class.getDeclaredMethod("getName");
MethodHandles.Lookup lookup = MethodHandles.publicLookup();
Class<?> declaringClass = getterMethod.getDeclaringClass();
Class<?> returnType = getterMethod.getReturnType();
CallSite getterSite = LambdaMetafactory.metafactory(lookup,
"apply",
MethodType.methodType(Function.class),
MethodType.methodType(Object.class, Object.class),
lookup.findVirtual(declaringClass, getterMethod.getName(), MethodType.methodType(returnType)),
MethodType.methodType(propertyType, declaringClass));
Function getterFunction = (Function) getterSite.getTarget().invokeExact();
Run Code Online (Sandbox Code Playgroud)
但是,如果该getterMethod方法来自从不同 ClassLoader 加载的类,则会抛出:
Caused by: java.lang.invoke.LambdaConversionException: Invalid caller: java.lang.Object
at java.lang.invoke.AbstractValidatingLambdaMetafactory.<init>(AbstractValidatingLambdaMetafactory.java:118)
at java.lang.invoke.InnerClassLambdaMetafactory.<init>(InnerClassLambdaMetafactory.java:155)
at java.lang.invoke.LambdaMetafactory.metafactory(LambdaMetafactory.java:299)
Run Code Online (Sandbox Code Playgroud)
如何将我的ClassLoader实例传递给LambdaMetafactory?
我需要一种方法来访问具有反射性质的字段,而不会受到标准反射的性能影响。我已经想出了如何使用特权查找句柄通过 LambdaMetaFactory 使用方法/构造函数执行此操作,但是,我似乎无法弄清楚如何获得字段访问权限。
我以为我可以通过类似 javaassist 的东西生成一个内部类,理论上应该可以访问该字段,但没有成功,抛出一个 IllegalAccessError。
如果我可以重新定义类,那么任务将是微不足道的,因为我可以生成 getter/setter 方法。但是,对于我正在处理的项目,我无法使用代理,因为它需要在运行时加载,而且我必须从工具动态导入附加 api。
任何人都可以在这里指导我正确的方向吗?我研究了 LambdaMetaFactory 如何为方法生成它的接口,并试图用字段来镜像它,但没有成功。如果不重新定义,字段和方法是否有内部不同的东西使这项任务变得不可能?
基于this stackoverflow answer,我试图使用反射实例化一个类,然后使用它调用一个单参数方法LambdaMetafactory::metafactory(我尝试使用反射,但它很慢)。
更具体地说,我想创建 的一个实例com.google.googlejavaformat.java.Formatter,并formatSource()使用以下签名调用其方法:String formatSource(String input) throws FormatterException.
我定义了以下功能接口:
@FunctionalInterface
public interface FormatInvoker {
String invoke(String text) throws FormatterException;
}
Run Code Online (Sandbox Code Playgroud)
并试图执行以下代码:
try (URLClassLoader cl = new URLClassLoader(urls.toArray(new URL[urls.size()]))) {
Thread.currentThread().setContextClassLoader(cl);
Class<?> formatterClass =
cl.loadClass("com.google.googlejavaformat.java.Formatter");
Object formatInstance = formatterClass.getConstructor().newInstance();
Method method = formatterClass.getMethod("formatSource", String.class);
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle methodHandle = lookup.unreflect(method);
MethodType type = methodHandle.type();
MethodType factoryType =
MethodType.methodType(FormatInvoker.class, type.parameterType(0));
type = type.dropParameterTypes(0, 1);
FormatInvoker formatInvoker = (FormatInvoker)
LambdaMetafactory …Run Code Online (Sandbox Code Playgroud) 我正在尝试通过 LambdaMetafactory 动态创建 BiConsumer 类型的方法引用。我试图应用在https://www.cuba-platform.com/blog/think-twice-before-using-reflection/上找到的两种方法 - createVoidHandlerLambda 和这里Create BiConsumer as Field setter 而不反映Holger 的答案。
但是在这两种情况下我都遇到以下错误:
Exception in thread "main" java.lang.AbstractMethodError: Receiver class org.home.ref.App$$Lambda$15/0x0000000800066040 does not define or inherit an implementation of the resolved method abstract accept(Ljava/lang/Object;Ljava/lang/Object;)V of interface java.util.function.BiConsumer.
at org.home.ref.App.main(App.java:20)
Run Code Online (Sandbox Code Playgroud)
我的代码是这样的:
public class App {
public static void main(String[] args) throws Throwable {
MyClass myClass = new MyClass();
BiConsumer<MyClass, Boolean> setValid = MyClass::setValid;
setValid.accept(myClass, true);
BiConsumer<MyClass, Boolean> mappingMethodReferences = createHandlerLambda(MyClass.class);
mappingMethodReferences.accept(myClass, true);
}
@SuppressWarnings("unchecked")
public …Run Code Online (Sandbox Code Playgroud) CallSite lambdaFactory = LambdaMetafactory.metafactory(
lookup,
"call",
MethodType.methodType(BiConsumer.class),
MethodType.methodType(void.class,Long.class),
lookup.findVirtual(CallClass.class, "call",
MethodType.methodType(void.class,Long.class)),
MethodType.methodType(void.class));
lambdaFactory.getTarget().invoke(callId);
private void call(Long callId){
---
}
Run Code Online (Sandbox Code Playgroud)
我收到此异常 java.lang.invoke.LambdaConversionException: 实例方法 invokeVirtual 调用的参数数量不正确:()void; 0 个捕获参数、0 个功能接口方法参数、0 个实现参数