3

I try to redefine simple non-static method but I get an exception:

Exception in thread "main" java.lang.UnsupportedOperationException: class redefinition failed: attempted to change the schema (add/remove fields)

Classes:

class Source { 
  def hello(name: String): String = "" 
}

class Target {
  def hello(name: String): String = "Hello" + name + "!"
}

Call:

 new ByteBuddy()
      .rebase(classOf[Source])
      .method(ElementMatchers.named("hello"))
      .intercept(MethodDelegation.to(new Target))
      .make()
      .load(classOf[Source].getClassLoader, ClassReloadingStrategy.fromInstalledAgent())
      .getLoaded
      .newInstance()
      .hello("World")

Classes above are scala classes but they compile to standard java classes.

How to redefine method correctly?

nigredo
  • 41
  • 2
  • Currently I can't make your code work in Java either. Maybe if we fix its behavior in Java, this helps in Scala. https://gist.github.com/DmytroMitin/266eb6cbeb9b788516c99c81f749ddc6 – Dmytro Mitin Sep 20 '17 at 19:49
  • @DmytroMitin you should explicitly set javaagent. I do it as follows -javaagent:D:/tmp/byte-buddy-agent-1.7.5.jar in my sbt file - `javaOptions in run ++= Seq( "-javaagent:D:/tmp/byte-buddy-agent-1.7.5.jar" )` – nigredo Sep 26 '17 at 06:30
  • Thank you for your response. For me this doesn't work. I still have `IllegalStateException: The Byte Buddy agent is not installed or not accessible`: https://gist.github.com/DmytroMitin/a2dae7e2bac2611d2f2c46a5ae2c08f9 – Dmytro Mitin Sep 26 '17 at 07:28
  • @DmytroMitin try to set fork := true in build.sbt – nigredo Sep 27 '17 at 17:08

2 Answers2

1

What you are trying to to is currently not supported by the JVM, you cannot add or remove fields or methods from any class what is an implict consequence of rebasing.

What you can do instead is redefining a class with ByteBuddy::redefine. This way, Byte Buddy replaces the original implementation instead of retaining it for potential invocation. In order to make this work, you also need to delegate to a stateless (startic) method as follows:

public class Target {
  public static String hello() {
    return "Hello" + name + "!"
  }
}

with a delegation: MethodDelegation.to(Target.class). This is necessary because otherwise, Byte Buddy would need to add a field to the instrumented class to store the delegation instance what is impossible with redefinition.

Alternatively, have a look at the Advice class which allows you to inline code what is compatible to rebasement where the original implementation is retained.

Rafael Winterhalter
  • 42,759
  • 13
  • 108
  • 192
  • redefine produces the same exception. About Advice is it possible in bytebuddy to get method body and change it? – nigredo Sep 23 '17 at 18:12
  • You are using method delegation to an instance what requires Byte Buddy to define a field to carry the target instance. Declare the interception method as static and delegate to the class rather than to an instance. – Rafael Winterhalter Sep 23 '17 at 20:27
  • I meant change method body not call some code after or before method. e.g. I have method body bytecode `inst1, inst2, inst3`. What I wanna do is add custom instructions between inst1 and inst2 Thus is its possible to do it in bytebuddy? – nigredo Sep 26 '17 at 06:34
  • This is possible using the underlying ASM API. Instruction level insrumentation requires a lot of manual work, unfortunately and ASM is already as good as it gets here. – Rafael Winterhalter Sep 26 '17 at 06:48
-2

This github issue (https://github.com/raphw/byte-buddy/issues/14) seems to indicate that byte-buddy doesn't support classes compiled by scala.

Levi Ramsey
  • 18,884
  • 1
  • 16
  • 30
  • I know about this issue but my classes will be generated to`public class Source { public String hello(String name) { return "" } }` and `public class Target { public String hello(String name) { return "Hello" + name + "!"; } }`. Thus I think byte buddy have to work with it – nigredo Sep 20 '17 at 16:22
  • @LeviRamsey It doesn't but anyway their "Hello World" works in Scala: https://gist.github.com/DmytroMitin/5c5eba88cd58bfdbedb37324308f0795 – Dmytro Mitin Sep 20 '17 at 19:44