Art*_*lan 16 java generics lambda
好吧,我们有FunctionalInterface
:
public interface Consumer<T> {
void accept(T t);
}
Run Code Online (Sandbox Code Playgroud)
我可以像以下一样使用它:
.handle(Integer p -> System.out.println(p * 2));
Run Code Online (Sandbox Code Playgroud)
我们如何generic type
在代码中解析lambda参数的实际值?
当我们将它用作内联实现时,Integer
从该类的方法中提取它并不困难.
我想念什么吗?或者只是java不支持lambda类?
为了更清洁:
那个lambda被包裹着MethodInvoker
(在提到中handle
),它在其execute(Message<?> message)
提取实际参数中进行进一步的反射方法调用.在此之前,它使用Spring将提供的参数转换为目标参数ConversionService
.
handle
在这种情况下,该方法是在实际应用程序工作之前的一些配置器.
不同的问题,但期望同一问题的解决方案:Java:使用lambda参数获取实际类型的泛型方法
Jon*_*han 12
我最近添加了对解决TypeTools的 lambda类型参数的支持.例如:
MapFunction<String, Integer> fn = str -> Integer.valueOf(str);
Class<?>[] typeArgs = TypeResolver.resolveRawArguments(MapFunction.class, fn.getClass());
Run Code Online (Sandbox Code Playgroud)
已解析的类型args如预期:
assert typeArgs[0] == String.class;
assert typeArgs[1] == Integer.class;
Run Code Online (Sandbox Code Playgroud)
注意:底层实现使用@danielbodart概述的ConstantPool方法,该方法已知可用于Oracle JDK和OpenJDK.
Dan*_*art 10
这目前可以解决,但只是以一种非常讨厌的方式,但我先解释一下:
编写lambda时,编译器会插入一个指向LambdaMetafactory的动态调用指令和一个带有lambda主体的私有静态合成方法.常量池中的合成方法和方法句柄都包含泛型类型(如果lambda使用类型或在示例中是显式的).
现在,在运行时LambdaMetaFactory
调用并使用实现功能接口的ASM生成类,然后方法的主体使用传递的任何参数调用私有静态方法.然后使用Unsafe.defineAnonymousClass
(参见John Rose帖子)将其注入原始类中,以便它可以访问私有成员等.
不幸的是,生成的类不存储通用签名(它可以),所以你不能使用通常的反射方法,让你绕过擦除
对于普通类,您可以使用Class.getResource(ClassName + ".class")
但是对于使用Unsafe
您定义的匿名类检查字节码是运气不好的.但是,您可以LambdaMetaFactory
使用JVM参数将它们转储出来:
java -Djdk.internal.lambda.dumpProxyClasses=/some/folder
Run Code Online (Sandbox Code Playgroud)
通过查看转储的类文件(使用javap -p -s -v
),可以看到它确实调用了静态方法.但问题仍然是如何从Java本身获取字节码.
不幸的是,这是hackie的地方:
使用反射我们可以调用Class.getConstantPool
然后访问MethodRefInfo来获取类型描述符.然后我们可以使用ASM来解析它并返回参数类型.把它们放在一起:
Method getConstantPool = Class.class.getDeclaredMethod("getConstantPool");
getConstantPool.setAccessible(true);
ConstantPool constantPool = (ConstantPool) getConstantPool.invoke(lambda.getClass());
String[] methodRefInfo = constantPool.getMemberRefInfoAt(constantPool.size() - 2);
int argumentIndex = 0;
String argumentType = jdk.internal.org.objectweb.asm.Type.getArgumentTypes(methodRef[2])[argumentIndex].getClassName();
Class<?> type = (Class<?>) Class.forName(argumentType);
Run Code Online (Sandbox Code Playgroud)
更新了乔纳森的建议
现在理想情况下,生成的类LambdaMetaFactory
应该存储泛型类型签名(我可能会看到我是否可以向OpenJDK提交补丁)但是目前这是我们能做的最好的.上面的代码有以下问题:
归档时间: |
|
查看次数: |
22492 次 |
最近记录: |