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、コンストラクター用の特定のバイト コードを作成する独自のインストルメンテーションを作成する必要があります。これはもちろん Byte Buddy に実装できますが、生成されたクラスの詳細がすべてわかっている場合は、 javacInstrumentationを使用してこのクラスをコンパイルすることをお勧めします。API について学びたいと思いますが、これは作成しようとしている実際のクラスではありません。

サンプル クラスでは、コンストラクターの desugared バージョンに相当するものを実装する必要があります。コンストラクターは 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 に答える