【问题标题】:How in Java to assign to fields with Byte Buddy?如何在 Java 中使用 Byte Buddy 分配给字段?
【发布时间】:2014-09-02 20:56:25
【问题描述】:

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

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

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

【问题讨论】:

    标签: java bytecode byte-buddy


    【解决方案1】:

    您正在使用自定义字节码创建一个类。为此,您不能使用内置的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,用于查询写入字节码指令。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多