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

时间:2017-03-30 20:46:31

标签: java bytecode-manipulation byte-buddy

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

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实现类概述?

  3. 如果没有这样的实现开箱即用,我会很感激有关如何使我自己的实现实例满足我的目的的一些提示。

2 个答案:

答案 0 :(得分:0)

没有找到任何准备好的实现,所以最终编写自己的。它尚未最终确定,但它确实有效。这是:

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;
    }
}

我会暂时搁置这个问题,因为有人知道更好的解决方案。

答案 1 :(得分:0)

您可以通过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);

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