Java中如何使用Byte Buddy分配字段?
我很难理解Byte Buddy的文档。 为了帮助我学习API,我想生成与此Java相当的字节代码:
public final class GeneratedByByteBuddy { private final int a; public GeneratedByByteBuddy(final int a) { this.a = a; } }
我很难找到使用Instrumentation
创建字段分配的正确方法。
您正在创建一个具有自定义字节代码的类。 为此,您不能使用内置Instrumentation
但您需要编写自己的检测,为构造函数创建特定的字节代码。 这个Instrumentation
当然可以为Byte Buddy实现,但是如果你知道关于你生成的类的所有细节,那么使用javac编译这个类会更好。 我假设你想要了解API,这不是你想要创建的实际类。
对于您的示例类,您需要实现构造函数的desugared版本的等效项。 构造函数只是Java运行时的方法,但它们遵循由JVM的validation程序强制执行的特定语义。 desberared构造函数看起来像:
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.>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
实现, Instrumentation
能够通过添加字段或方法来修改创建的类型。 这对你的class级来说不是必需的。 然后,它发出一个ByteCodeAppender
,用于查询字节码指令。