如何应用,删除和重新应用bytebuddy转换?

时间:2017-03-15 08:14:05

标签: java byte-buddy

我正在尝试通过javaagent apply, remove and re-apply进行bytebuddy转换,如下面的代码所示。删除通过ResettableClassFileTransformer::reset正常工作,但重新申请无效。

// The target classes

public @interface ToString {
}

public interface Greetable {
    String say(final String name);
}

@ToString
public class Greeter implements Greetable {
     public String say(final String name) {
         return "Hello " + name;
     }
}
//note the some transform is from the example
new AgentBuilder.Transformer() {
  @Override
  public DynamicType.Builder transform(DynamicType.Builder builder,
                                       TypeDescription     typeDescription,
                                       ClassLoader         classloader,
                                       JavaModule          module) {
    return builder.method(named("say"))
                  .intercept(FixedValue.value("transformed");
  }
})
// The transformation
public class MyProgram {
    public static void main(final String[] args) {
        ByteBuddyAgent.install();
        AgentBuilder bldr = new AgentBuilder.Default().
                                             with(AgentBuilder.Listener.
                                                      StreamWriting.
                                                      toSystemOut()).
                                             with(RedefinitionStrategy.
                                                     RETRANSFORMATION).
                                             disableClassFormatChanges().
                                             type(isSubTypeOf(
                                                       Greetable.class)).
                                             transform(<some transform>);
        ResettableClassFileTransformer resetter = 
                                          bldr.installOnByteBuddyAgent();
        Greetable g1 = new Greeter();
        System.out.println(g1.say("001"));

        //remove the transformation
        resetter.reset(ByteBuddyAgent.getInstrumentation(),
                       RedefinitionStrategy.RETRANSFORMATION);
        Greetable g2 = new Greeter();
        System.out.println(g2.say("002"));

        //re-apply the transformation
        bldr.installOn(ByteBuddyAgent.getInstrumentation());
        Greetable g3 = new Greeter();
        System.out.println(g3.say("003"));

    }
}

输出

TRANSFORM Greetable [sun.misc.Launcher$AppClassLoader@7ab2bfe1,
                     null,
                     loaded=true]
TRANSFORM Greeter [sun.misc.Launcher$AppClassLoader@7ab2bfe1,
                   null,
                   loaded=true]
transformed //note: the g1.say() is transformed.

Hello 002         //note: the g2 is an orginal

TRANSFORM Greetable [sun.misc.Launcher$AppClassLoader@7ab2bfe1,
                     null,
                     loaded=true]
TRANSFORM Greeter [sun.misc.Launcher$AppClassLoader@7ab2bfe1,
                   null,
                   loaded=true]
Hello 003         //note the re-apply has not worked.

请您帮忙建议如何重新申请?

EDIT1

我已将byte-buddy更新为版本1.6.11并更改了AgentBuilder.Transformer。结果仍然相同。 g3.say()未被转换。

我的环境是

Windows 10 64Bits

java version "1.8.0_60"
Java(TM) SE Runtime Environment (build 1.8.0_60-b27)
Java HotSpot(TM) 64-Bit Server VM (build 25.60-b23, mixed mode)

EDIT2

我已从界面

更改了类型匹配器
type(isSubTypeOf(Greetable.class))

到具体类

type(isSubTypeOf(Greeter.class))

g3.say()正在转变。接口匹配和转换是否有任何限制?

1 个答案:

答案 0 :(得分:1)

我正在使用AgentBuilder.Transformer API运行旧版Byte Buddy。我刚刚尝试使用最新版本,但它确实有效。

实际上,您是否依靠@ToString注释来触发转换?当您转换尚未加载的类时,Byte Buddy直接从类文件中读取注释。对于加载的类,它使用加载的表示。您的注释未使用@RetentionPolicy(Retention.RUNTIME)进行注释,以保留可能存在问题的注释可见性。

更新:您需要通过say从界面中排除not(isAbstract()).and(named("say"))方法来优化方法匹配器。否则,您在重新转换尝试中包含接口。由于在加载类之后无法将抽象方法更改为默认方法,因此JVM似乎默默地无法进行第二次重新转换。通常情况下,这会触发异常,但在您的情况下,VM似乎会默默地抑制错误。