如何使用ASM修改Java BootstrapMethods中的指令?

如何使用ASM修改Java BootstrapMethods中的指令?,java,java-bytecode-asm,Java,Java Bytecode Asm,在使用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/MethodT

在使用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

BootstrapMethods属性包含对其他方法的引用。您的类文件中(通常)没有引导方法,实际上您不想更改引导方法,即示例中类
java.lang.invoke.LambdaMetafactory
中的方法
metafactory

您实际想要做的(显然)是更改将为lambda表达式或方法引用创建实例的属性。对于此任务,ASM已经为您提供了帮助

使用Visitor API时,必须重写。此时,ASM已经解码了
BootstrapMethods
属性的引用条目,将这些值提供给visit方法,并将(重新)创建适当的
BootstrapMethods
属性,当您传递这些值时,可能会更改,
ClassWriter
的方法访问者的
visitInvokeDynamicInsn
方法的值

在被重写的
visitinVokeDynamicSn
中,首先必须验证该
invokedynamic
指令是否确实是lambda创建站点。
bsm
参数必须是所有者为
java/lang/invoke/LambdaMetafactory
的,并且方法必须是或。如果没有,只需将所有内容传递给
super.visitInvokeDynamicInsn
(委托给编写器不变),因为这是then的不同用法(例如,Java 9将使用它进行字符串连接)


当它是lambda创建站点时,可以根据中指定的约定解释参数。
bsmArgs
数组对应于您在问题中发布的属性。索引
1
处的数组元素将是目标方法,同样在ASM中表示。您可以将其更改为不同的手柄,这似乎是您的预期操作。目标函数接口是
desc
参数中编码的返回类型,函数接口方法的名称作为
name
参数提供(引导方法的
invokedName
name参数)。有关更多详细信息,请参阅。

作为lambda创建站点的句柄的getOwner方法不返回java/lang/invoke/LambdaMetafactory。你有没有其他方法来检查车主?你看的是正确的把手吗?
bsm
参数必须指向
LambdaMetafactory
bsmArgs
args数组中的句柄指向方法引用/lambda表达式的目标方法。