更新:行为在版本4.0.17 ( BYTEMAN-416 ) 中发生了变化,现在可以在 lambda 上触发规则
我能够使用BytemanTest
带有两个 lambda 的简单类(最后是源代码)来重现该问题。
简短的回答
Byteman忽略 lambda,因为它们在字节码中被编译器标记为“生成的代码”。
长答案:
(至少在我的测试中)编译器在生成的字节码中将 Lambda 标记为ACC_SYNTHETIC。
来自Java® 虚拟机规范:
ACC_SYNTHETIC 标志表明此方法是由编译器生成的,并且不会出现在源代码中,除非它是第 4.7.8 节中指定的方法之一。
以下是 的输出的摘录javap -v -p -s -c BytemanTest.class
:
...
private static java.lang.String lambda$doSomething$1(java.lang.String);
descriptor: (Ljava/lang/String;)Ljava/lang/String;
flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
Code:
...
private static void lambda$main$0(java.lang.String);
descriptor: (Ljava/lang/String;)V
flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
Code:
stack=3, locals=1, args_size=1
Byteman忽略具有标志ACC_SYNTHETIC的方法。
这种行为(可能)首先在这张票BYTEMAN-58中引入(在提交ac4cbb4f中。标志测试在*Adapter
类中)。
在 Byteman 的 v4.0.16 源代码中,匹配目标方法的测试在TransformContext#matchTargetMethod中完成,它忽略标记为ACC_SYNTHETIC的方法:
if ((access & (Opcodes.ACC_NATIVE|Opcodes.ACC_ABSTRACT|Opcodes.ACC_SYNTHETIC)) != 0 ||
!targetMethodName.equals(name) ||
(!targetDescriptor.equals("") && !TypeHelper.equalDescriptors(targetDescriptor, desc))) {
return false;
}
我的测试班
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class BytemanTest {
public static void main(String[] args){
BytemanTest bt = new BytemanTest();
bt.doSomething(args).forEach((s) -> {
System.out.println("Out : " + s);
});
}
public List<String> doSomething(String[] args){
return Arrays.stream(args).map( s -> s + "_test").collect(Collectors.toList());
}
}
我的 byteman 规则:
RULE showdir
CLASS BytemanTest
METHOD lambda$main$0
AT ENTRY
IF TRUE
DO System.out.println("lambda matched");
ENDRULE