byte-buddy icon indicating copy to clipboard operation
byte-buddy copied to clipboard

Side effects of bytebuddy rebasing to weaving process?

Open rage5474 opened this issue 1 year ago • 1 comments

Inspired from this stackoverflow question byte-buddy-and-osgi-weaving-hook, I tried following WeavingHook example with Eclipse RCP equinox runtime:

Code

// WeavingHookService.java
public class WeavingHookService implements WeavingHook {

  @Override
  public void weave(WovenClass wovenClass) {

    if (wovenClass.getClassName().endsWith("MyPrinter")) {
      try {
        byte[] originalBytes = wovenClass.getBytes();

        Unloaded<MyPrinter> newPrinter = new ByteBuddy()
            .rebase(MyPrinter.class,
                ClassFileLocator.Simple
                    .of(wovenClass.getClassName(),
                        originalBytes))
            .method(ElementMatchers.named("getName"))
            .intercept(FixedValue.value("Raphael"))
            .make();

        // setBytes has no effect.
        wovenClass.setBytes(newPrinter.getBytes());
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  }
}

// MyPrinter.java
public class MyPrinter {
  public String getName() {
    return "Unknown";
  }
}

Expectation My expectation is that if I call new MyPrinter().getName() in my code, Raphael is returned.

Observation If I call new MyPrinter().getName() in my code, Unknown is returned.

Already analyzed If I set a hard-coded byte array, like new byte[]{'0', '1'} instead of doing bytebuddy rebase call, setBytes throws at least some exception. But this does not happen, if a bytebuddy rebase call is done before setBytes is called.

Question So, for me it seems that the bytebuddy rebase call has side-effects to the weaving process. But maybe I am doing something wrong here. Does anybody have an idea what's going wrong?

rage5474 avatar Jul 01 '24 07:07 rage5474

Byte Buddy implements an immutable builder, there should be no side effects. Maybe the weaver fails as you refer to the loaded MyPrinter class?

You can use a TypePool to describe s class from class bytes.

raphw avatar Jul 01 '24 18:07 raphw

Thanks for the hint. This code is working fine for me. With this service it is even possible to modify not exported classes without modifying anything in the manifest. This is really great, because I can modify cross-cutting things in OSGi without using java agents.

@Component(immediate = true)
public class WeavingHookService implements WeavingHook {

  private static final String CLASS_TO_MODIFY = "my.waevinghook.example.internal.MyPrinter";

  @Override
  public void weave(WovenClass wovenClass) {

    if (wovenClass.getClassName().equals(CLASS_TO_MODIFY)) {
      try {
        byte[] originalBytes = wovenClass.getBytes();

        ClassFileLocator locator = ClassFileLocator.Simple
            .of(wovenClass.getClassName(),
                originalBytes);

        Unloaded<Object> newPrinter = new ByteBuddy()
            .rebase(TypePool.Default.of(wovenClass.getBundleWiring().getClassLoader())
                .describe(
                CLASS_TO_MODIFY).resolve(),
                locator)
            .method(ElementMatchers.named("getName"))
            .intercept(FixedValue.value("Raphael"))
            .make();

        wovenClass.setBytes(newPrinter.getBytes());
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  }
}

rage5474 avatar Jul 02 '24 07:07 rage5474