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

How to access an injected static field in Advice?

Open FrankChen021 opened this issue 3 years ago • 5 comments

Hello @raphw , I want to inject a static field, whose name is dynamically generated, to some classes, and how could I access this dynamic injected field in Advice class?

The code piece is as below:

String delegatorName; // holds a dynamic generated static field name 
builder
    .defineField(delegatorName, target, Ownership.STATIC, Visibility.PRIVATE)
    .initializer(new LoadedTypeInitializer() {
        @Override
        public void onLoad(Class<?> type) {
            try {
                Field field = type.getDeclaredField(delegatorName);
                field.setAccessible(true);
                field.set(null, Class.forName(interceptor, false, null).getConstructor().newInstance());
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }

        @Override
        public boolean isAlive() {
            return true;
        }
    })
    .visit(Advice.to(MyAdviceClass.class))


public class MyAdviceClass {
    @Advice.OnMethodEnter
    public static boolean onEnter() {
         // how could I access the injected static field here???
    }
}

FrankChen021 avatar Feb 19 '22 04:02 FrankChen021

Seems that I successfully did that by defining a custom attribute for the Advice class and binding that attribute to the dynamic field. Not sure if it's the best way to do that.


builder.defineField(fieldName, TypeDescription.OBJECT, Ownership.STATIC, Visibility.PRIVATE)
                              .initializer(new StaticFieldInitializer(fieldName, targetClassName))
                              .visit(Advice.withCustomMapping()
                                           .bind(Delegator.class, new DynamicFieldDescription(typeDescription, fieldName))
                                           .to(MyAdviceClass.class);


static class DynamicFieldDescription extends FieldDescription.InDefinedShape.AbstractBase {
      private final TypeDescription declaringType;
      private final String fieldName;

      DynamicFieldDescription(TypeDescription declaringType, String fieldName) {
          this.declaringType = declaringType;
          this.fieldName = fieldName;
      }

      @Override
      public TypeDescription getDeclaringType() {
          return declaringType;
      }

      @Override
      public TypeDescription.Generic getType() {
          return TypeDescription.OBJECT.asGenericType();
      }

      @Override
      public int getModifiers() {
          return ACC_PRIVATE | ACC_STATIC;
      }

      @Override
      public String getName() {
          return fieldName;
      }

      @Override
      public AnnotationList getDeclaredAnnotations() {
          return null;
      }
  }

public static MyAdviceClass {
 @Advice.OnMethodEnter
    public static boolean onEnter(final @Delegator Object delegator) {

    }
}

FrankChen021 avatar Feb 19 '22 05:02 FrankChen021

There's @Advice.FieldValue that can already bind a field. Have you tried using that?

raphw avatar Feb 19 '22 18:02 raphw

@raphw , Thanks for yoru response. I know the FieldValue annotation. but since the field name in my case is dynamic, how can I use it in the Advice class?

FrankChen021 avatar Feb 20 '22 03:02 FrankChen021

In this case, you would need to register your own OffsetBinding and resolve a field value dynamically. Have a look at the existing offset bindings for an example.

raphw avatar Feb 20 '22 08:02 raphw

The comment here I think did the right thing. https://github.com/raphw/byte-buddy/issues/1208#issuecomment-1045792392

FrankChen021 avatar Feb 20 '22 11:02 FrankChen021