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