使用Java 8编译并使用javap转储生成的类文件后,我看到了这一点,其中我只展示了前两个项目:
BootstrapMethods:
0: #174 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
Method arguments:
#175 (Ljava/lang/Object;)Z
#179 invokestatic llllll/lallll.lambda$printPersons$0:(Lllllll/lallll;)Z
#180 (Lllllll/lallll;)Z
1: #174 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
Method arguments:
#175 (Ljava/lang/Object;)Z
#191 invokestatic llllll/lallll.lambda$printPersons$1:(Lllllll/lallll;)Z
#180 (Lllllll/lallll;)Z
2: #174 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/inv
我可以使用ASM访问这些引导方法中的指令,并更改上面使用invokestatic指令调用的方法的名称吗?
显然这些方法不是类的常规方法的一部分,我没有运气使用标准的ASM类和方法技术来访问它们。
如果不使用ASM,是否可以使用另一个Java字节码/类文件操作框架查找和修改这些指令?
我一直在阅读Java的标准类文件格式文档,我没有看到有关引导方法的指令的直接描述,但我确实看到了我将描述为引导方法的元数据。
感谢,
-David
答案 0 :(得分:1)
BootstrapMethods
属性包含引用到其他方法。您的类文件中没有引导方法(通常),并且您实际上不希望更改引导方法,即示例中类metafactory
中的方法java.lang.invoke.LambdaMetafactory
。
您实际想要做的事情(显然)是更改将为lambda表达式或方法引用创建实例的invokedynamic
instruction的属性。对于此任务,ASM已经为您提供了帮助。
使用访客API时,您必须覆盖visitInvokeDynamicInsn
。在这个地方,ASM已经解码了BootstrapMethods
属性的引用条目,为访问方法提供了这些值,并且当您传递这些可能已更改的值时,将(重新)创建相应的BootstrapMethods
属性到visitInvokeDynamicInsn
方法访问者的ClassWriter
方法。
在重写的visitInvokeDynamicInsn
中,首先必须验证此invokedynamic
指令是否真的是lambda创建站点。 bsm
参数必须是Handle
,其所有者为java/lang/invoke/LambdaMetafactory
且该方法必须为metafactory
或altMetafactory
。如果没有,只需将所有内容传递给super.visitInvokeDynamicInsn
(委托给作者不变),因为它是对invokedynamic
feature的不同用法(例如,Java 9将使用它进行字符串连接)。
当它是lambda创建站点时,您可以根据the documentation of LambdaMetafactory
中指定的约定来解释参数。 bsmArgs
数组对应于您在问题中发布的属性。索引1
处的数组元素将是目标方法,在ASM中再次表示为Handle
。您可以将其更改为不同的句柄,这似乎是您的预期操作。目标功能接口是在desc
参数中编码的返回类型,功能接口的方法名称以name
参数(bootstrap方法的invokedName
name参数)提供。有关详细信息,请参阅LambdaMetafactory
’s comprehensive documentation。