在 ByteBuddy 中从头开始创建一个 class 构造函数

Create a class constructor from scratch in ByteBuddy

我正在尝试使用 ByteBuddy 从头开始​​创建 Java class。 class 应该有一堆私有的最终属性和一个用传递的参数初始化它们的构造函数。我开始于:

DynamicType.Builder<?> builder = new ByteBuddy()
                .subclass(Object.class)
                .implement(Serializable.class)
                .modifiers(Visibility.PUBLIC, TypeManifestation.FINAL)
                .name("Structure");

// for each property to be declared
builder = builder.defineField(bindingName, bindingType, visibility.PRIVATE, FieldManifestation.FINAL);
// end of for

builder = builder.defineConstructor(Visibility.PUBLIC)
                .withParameters(bindings)
                .intercept(/* Some implementation is supposed to go here*/);

我有几个问题:

  1. ByteBuddy 是否提供了一些开箱即用的合适实现?

  2. 是否有开箱即用的 ByteBuddy 实施 classes 概述?

  3. 如果没有这样的开箱即用的实现,我将不胜感激关于如何制作我自己的实现实例服务于我的目的的一些提示。

没有找到任何现成的实现,所以最后写了我自己的。它没有最终确定,但它有效。这是:

final class ConstructorImplementation implements Implementation {

    static private final class BCA implements ByteCodeAppender {

        @Override
        public Size apply(MethodVisitor methodVisitor, Context implementationContext, MethodDescription instrumentedMethod) {
            TypeDescription instrumentedType = implementationContext.getInstrumentedType();
            Iterator<? extends ParameterDescription> iterator = instrumentedMethod.getParameters().iterator();

            List<StackManipulation> insr = new ArrayList<>();
            insr.add(MethodVariableAccess.loadThis());
            insr.add(MethodInvocation.invoke(TypeDescription.OBJECT.getDeclaredMethods().get(0)));
            for (FieldDescription.InDefinedShape field : instrumentedType.getDeclaredFields()) {
                ParameterDescription.InDefinedShape param = iterator.next().asDefined();
                insr.add(MethodVariableAccess.loadThis());
                insr.add(MethodVariableAccess.load(param));
                insr.add(FieldAccess.forField(field).write());
            }
            insr.add(MethodReturn.VOID);

            StackManipulation.Size operandStackSize = new StackManipulation.Compound(
                    insr
            ).apply(methodVisitor, implementationContext);
            return new Size(operandStackSize.getMaximalSize(),
                    instrumentedMethod.getStackSize());
        }
    }

    private final BCA bca;

    public ConstructorImplementation() {
        bca = new BCA();
    }

    @Override
    public ByteCodeAppender appender(Target implementationTarget) {
        return bca;
    }

    @Override
    public InstrumentedType prepare(InstrumentedType instrumentedType) {
        return instrumentedType;
    }
}

我会暂时搁置这个问题,以防万一有人知道更好的解决方案。

您可以通过 MethodCallFieldAccessor 的组合来实现这样的构造函数:

DynamicType.Builder<?> builder = ...;
Implementation interceptor = StubMethod.INSTANCE;

// for each field
builder = builder.defineField(bindingName, 
              bindingType, visibility.PRIVATE, FieldManifestation.FINAL);
interceptor = FieldAccessor.ofField(bindingName)
                  .setsArgumentAt( ... )
                  .andThen(interceptor);

interceptor = MethodCall.invoke( ... ).andThen(interceptor);

方法调用必须调用已检测 class 或超级 class 构造函数(可能是 Object 的默认构造函数)的特定构造函数。参数索引需要是分配给字段的参数索引(从零开始)。