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

Wrapper around method code

Open rupinder10 opened this issue 1 year ago • 6 comments

I have a method like:

public void checkName(String name) {
//Some code here
}

I would like to instrument this as under:

File file = Utils.getTempFile();
try (FileWriter fw = new FileWriter(file)) {
  fw.write(new Date().toString());
  // Call original code of checkName <----
}

I tried

@RuntimeType
public static void intercept(@Origin Method m, @SuperCall Callable<?> zuper) throws Exception {
  File file = Utils.getTempFile();
  try (FileWriter fw = new FileWriter(file)){
    fw.write(new Date().toString());
    zuper.call();
  }
}

But that gave me an error that

None of [public static void test.MethodWrapper.intercept(java.lang.reflect.Method,java.util.concurrent.Callable) throws java.lang.Exception] 
allows for delegation from public void MyClass.checkName(java.lang.String)

How do I achieve this ?

rupinder10 avatar Jun 21 '23 02:06 rupinder10

Do you rebase? With a redefinition, static methods do not have a super method and the delegator could not be bound.

raphw avatar Jun 21 '23 20:06 raphw

I will have to confess that I dont understand those details. I am totally new to ByteBuddy and trying to understand the terms. If you have a suggestion as to how to achieve a wrapper around my method code that use a try-with-resources, I am willing to try any option

rupinder10 avatar Jun 22 '23 03:06 rupinder10

Can you show how your Byte Buddy code looks like? How do you apply the delegation?

raphw avatar Jun 22 '23 10:06 raphw

I tweaked the code a bit but still getting the same issue. It seems it looks for @OnMethodEnter and @OnMethodExit annotations in the Advice class. Here is the code I am using:

  AgentBuilder.Transformer transformer =
        new AgentBuilder.Transformer() {
          @Override
          public Builder<?> transform(
              Builder<?> builder,
              TypeDescription typeDescription,
              ClassLoader classLoader,
              JavaModule module,
              ProtectionDomain protectionDomain) {
             return builder
                .method(ElementMatchers.named("invoke"))
                .intercept(Advice.to(MethodProfiler.class));
          }
        };

    AgentBuilder builder =
        new AgentBuilder.Default()
            .with(RedefinitionStrategy.RETRANSFORMATION)
            .disableClassFormatChanges();
    Narrowable narrowable = builder.type(ElementMatchers.nameEndsWith("InvokeManager"));
    Extendable extendable = narrowable.transform(transformer);
    ResettableClassFileTransformer resettableClassFileTransformer =
        extendable.installOn(instrumentation);

The code for MethodProfiler class is :

public class MethodProfiler {
	public static void intercept(@SuperCall Callable<?> zuper) {
		try {
			File file = File.createTempFile("test", "tmp");
			try (FileWriter fw = new FileWriter(file)) {
				fw.write(new Date().toString());
				zuper.call();
			}
		} catch (Exception e) {

		}
	}
}

and the signature of the method being instrumented is

public void invoke(Iterable iterable, String st1, String st2);

rupinder10 avatar Jun 22 '23 17:06 rupinder10

Since I could not make this work, I decided go with the visitor approach to add onMethodEnter and onMethodExit to fake a wrapper. Would like to take a look at this someday to see what I did wrong, but not needed for now

rupinder10 avatar Jun 27 '23 02:06 rupinder10

I am currently rewriting business logic for the static method @onMethodExit through redefine and visitor. The actual test can achieve the effect. But there is also a new problem: there is no problem to run the program directly with idea, but it does not work when packaged into jar. issue1470

SuperDubbo avatar Jul 01 '23 12:07 SuperDubbo