raphw / byte-buddy

Runtime code generation for the Java virtual machine.
https://bytebuddy.net
Apache License 2.0
6.23k stars 804 forks source link

Replace Method Code #1583

Closed rupinder10 closed 6 days ago

rupinder10 commented 8 months ago

I have a method with some complex logic. Deep in the code there is an operation on a field value that I would like to change. I thought of implementing this with an Advice class with a onMethodExit. The problem with that is that then the original code executes and then the modified code executes. This is pretty inefficient because the original code is pretty complex. This is an already loaded class.

protected Set cache = Collections.synchronizedSet(new HashSet());

private boolean updateCache(File jarDir) {
  zFile = new ZipFile(jarDir);
  Enumeration zipEntry = zFile.entries();

  while(zipEntry.hasMoreElements()) {
    ZipEntry entry = (ZipEntry)zipEntry.nextElement();
    if (!entry.isDirectory()) {
      this.cache.add(entry.getName()); // This is the line I would like to change with some alternate logic
    }
  }
  return true;
}

The other option is to use MethodDelegation but then I am not sure how that can refer to the class fields. We use the field cache in this case. What is the best way to achieve this kind of instrumentation.

raphw commented 8 months ago

In advice, you can skip the original code. Look at: OnMethodEnter(skipOn = ...).

A common way of doing this is:

class MyAdvice {
  @Advice.OnMethodEnter(skipOn = Advice.NonDefaultValue.class)
  static boolean onEnter(@Advice.Local Object returnValue) {
    if (...) {
      // do alternative
      returnValue = ...;
      return true;
     } else {
       return false;
     }
  }

  @Advice.OnMethodExit
   static void exit(@Advice.Enter boolean skipped, @Advice.Local Object returnValue, @Advice.Return Object returnedValue) {
     if (skipped) {
       returnedValue = returnValue;
     }
   }
}
rupinder10 commented 8 months ago

Advice.NonDefaultValue.class

This worked. Thanks @raphw. I do have a question about what exactly does this mean ?

skipOn = Advice.NonDefaultValue.class
raphw commented 8 months ago

The default value is null, false or 0. It means that if this default value is returned, the method is not skipped, in this case. It's also explained in the javadoc.