【问题标题】:Create a class constructor from scratch in ByteBuddy在 ByteBuddy 中从头开始创建类构造函数
【发布时间】:2017-04-02 01:30:50
【问题描述】:

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

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. 如果没有这样的开箱即用实现,我将不胜感激有关如何使我自己的实现实例服务于我的目的的一些提示。

【问题讨论】:

    标签: java bytecode-manipulation byte-buddy


    【解决方案1】:

    你可以通过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 的默认构造函数)。参数索引需要是分配给字段的参数的索引(从零开始)。

    【讨论】:

      【解决方案2】:

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

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-05-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多