3

最新的 Byteman 文档 (4.0.16) 提到了内部类,但没有提到 lambdas。我有一个看起来像的规则:

RULE showdir
CLASS ReportService
METHOD lambda$retrieveReport$0
AT ENTRY
IF TRUE
DO System.out.println("XXXXXXXX");
ENDRULE

然而,它似乎永远不会触发。当我运行不带参数的 bmsubmit 时,它会显示规则但没有提及触发方法。我用javap检查了方法名,是正确的。我可以触发此类的其他非 lambda 方法。我在 Alpine Linux 上运行 AdoptOpenJdk 8。

Byteman 是否支持 lambda?我需要做其他事情来触发规则吗?

4

2 回答 2

2

嗯,从 javap 反编译中获取实现 lambda 主体的方法的名称是识别目标方法的巧妙技巧。我不确定为什么 Byteman 没有注入 coe。你能通过 Byteman JIRA 实例报告这个吗?我将在 JIRA 上进行调查并报告结果。实际上可能使这项工作成为可能。

于 2021-07-29T14:27:01.587 回答
1

更新:行为在版本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
于 2021-07-31T21:37:20.030 回答