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