【问题标题】:How to redefine lambda anonymous class in java如何在java中重新定义lambda匿名类
【发布时间】:2016-10-26 02:57:13
【问题描述】:

JDK8将lambda表达式转换为匿名类

InnerClassLambdaMetafactory.spinInnerClass() {
    return UNSAFE.defineAnonymousClass(targetClass, classBytes, null);
}

我正在写一个javaagent,使用asm修改classBytes(添加一个方法)并传递给defineAnonymousClass,但是这个方法最终得到了这个匿名类的ClassNotFoundException。有什么办法可以修改匿名 classBytes 的内容?

【问题讨论】:

    标签: java lambda java-8 javaagents


    【解决方案1】:

    转换匿名加载的类很棘手。您是否正在重新转换已加载的代表此类类的类?如果是这样,请注意Class::getName 不会返回类的实际二进制名称,而是添加一个随机哈希,例如my.DefinedType/12345,您需要在其中去除最新的数字。

    此外,您不能直接从另一个类引用此类类,但您需要直接从反射 API 或理想的方法句柄引用它们。您无法从类加载器中查找此类类,这就是它们被称为匿名的原因。

    最后,在安装类文件转换器时,此类匿名类的加载不会向转换器注册。处理此类类的最简单方法是修补负责创建 lambda 类型的 lambda 元工厂。您可以通过使用例如Byte Buddy 轻松地做到这一点,它允许您创建代理:

    new AgentBuilder.Default()
      .with(LambdaTransformationStrategy.ENABLED)
      .type(someMatcher)
      .transform(someTransformer)
      .installOn(instrumentation);
    

    调用它,在幕后,Byte Buddy 重写了 JVM 的默认 lambda 元工厂类,并将其替换为它自己的代码生成,在这种情况下是可能的。

    【讨论】:

    • 其他类可以直接引用匿名类,如果它们也是匿名类并且有一个补丁常量池(这是defineAnonymousClass的第三个参数)。在这种情况下,他们使用哪个名称也没关系。
    • 确实如此。但这不适用于描述 lambda 表达式的类。
    • 感谢您的回答,我不是要重新转换已经加载的类,而是在创建匿名类之前修改它的字节。仍然不知道为什么它不起作用。用targetClass.getClassLoader.defineClass(modifyedAnonymousClassBytes) 定义匿名类怎么样?有没有副作用?
    • @nzomkxia:当您尝试在加载时更改类的字节码时,您必须在ClassFileTransformer 的实现中进行。在这种情况下,您既不应该调用defineClass 也不应该调用defineAnonymousClass,而应该简单地返回 修改后的字节码。将字节码传递给 targetClass 的 defineClass 方法ClassLoader 很少起作用。首先,匿名类可以访问目标类的private 方法,这对于普通类是不允许的,其次,targetClass 可能是一个引导类,具有null 类加载器。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-24
    • 1970-01-01
    • 2018-04-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多