4

我很难理解Byte Buddy的文档。为了帮助我学习 API,我想生成与这个 Java 等效的字节码:

    public final class GeneratedByByteBuddy {
        private final int a;
        public GeneratedByByteBuddy(final int a) {
            this.a = a;
        }
    }

我很难找到正确的方法Instrumentation来创建字段分配。

4

1 回答 1

6

您正在使用自定义字节码创建一个类。为此,您不能使用内置的,Instrumentation但您需要编写自己的工具,为您的构造函数创建特定的字节码。这Instrumentation当然可以为 Byte Buddy 实现,但是如果您了解生成的类的所有细节,最好使用javac编译这个类。我假设您想了解 API,而这不是您要创建的实际类。

对于您的示例类,您需要实现构造函数的脱糖版本的等效项。构造函数只是 Java 运行时的方法,但它们遵循由 JVM 验证程序强制执行的特定语义。脱糖构造函数如下所示:

public GeneratedByByteBuddy(int a) {
  super();
  this.a = a;
  return;
}

这个类的 Byte Buddy 实现如下所示:

new ByteBuddy()
  .subclass(Object.class, ConstructorStrategy.Default.NO_CONSTRUCTORS)
  .name("my.company.GeneratedByByteBuddy")
  .defineField("a", int.class, Visibility.PRIVATE, FieldManifestation.FINAL)
  .defineConstructor(Arrays.<Class<?>>asList(int.class), Visibility.PUBLIC)
  .intercept(new Instrumentation() {
    @Override
    public InstrumentedType prepare(InstrumentedType instrumentedType) {
      return instrumentedType;
    }

    @Override
    public ByteCodeAppender appender(final Target instrumentationTarget) {
      return new ByteCodeAppender() {
        @Override
        public boolean appendsCode() {
          return true;
        }

        @Override
        public Size apply(MethodVisitor methodVisitor,
                          Context instrumentationContext,
                          MethodDescription instrumentedMethod) {
          StackManipulation.Size size = new StackManipulation.Compound(
            MethodVariableAccess.REFERENCE.loadFromIndex(0),
            MethodInvocation.invoke(new TypeDescription.ForLoadedType(Object.class)
              .getDeclaredMethods()
              .filter(isConstructor().and(takesArguments(0))).getOnly()),
            MethodVariableAccess.REFERENCE.loadFromIndex(0),
            MethodVariableAccess.INTEGER.loadFromIndex(1),
            FieldAccess.forField(instrumentationTarget.getTypeDescription()
              .getDeclaredFields()
              .named("a"))
              .putter(),
            MethodReturn.VOID
          ).apply(methodVisitor, instrumentationContext);
          return new Size(size.getMaximalSize(), instrumentedMethod.getStackSize());
        }
      };
    }
  })
  .make()
  .load(getClass().getClassLoader(), ClassLoadingStrategy.Default.INJECTION);

每个方法实现都由一个Instrumentation能够通过添加字段或方法来修改创建的类型的实现。这对您的课程不是必需的。然后,它发出一个ByteCodeAppender用于编写字节码指令的查询。

于 2014-07-14T11:03:57.233 回答