如何让ByteBuddy构建一个类实现并初始化成员变量?

时间:2018-03-12 17:51:09

标签: java byte-buddy

我一直在广泛搜索但没有成功,在示例中找不到答案。

拥有以下成员的课程:

public class Foo {
  public String name;
  public Long age;
}

我想构建一个这个类的新实现,通过委托给某个initliaiser类来初始化成员变量。

Bar dynamicType = new ByteBuddy(ClassFileVersion.JAVA_V8)
                .subclass(Foo)
                .initializer(new BarInit())
                .make()
                .load(Foo.class.getClassLoader(), WRAPPER)
                .getLoaded()
                .newInstance();

也创建了

public class BarInit implements LoadedTypeInitializer {
    @Override
    public void onLoad(Class<?> type) {
       Field[] fields = type.getDeclaredFields();
       // fields is empty?!
    }

    @Override
    public boolean isAlive() {
        return true;
    }
}

我想我已经失去了密码。我需要一个提示。

所以经过一些提示我转到了

public class Foo {

    public Foo() {
    }

    public Foo(Bar qClass) {
        this();
    }

  public String name;
  public Long age;
}

FooBar dynamicType = new ByteBuddy(ClassFileVersion.JAVA_V8)
        .subclass(Foo)
        .defineConstructor(PUBLIC)
                .withParameter(Bar.class, "initClass")
                .intercept(SuperMethodCall.INSTANCE
                .andThen(MethodDelegation.to(new Interceptor())))
        .make()
        .load(getClass().getClassLoader())
        .getLoaded()
        .getDeclaredConstructor(Bar.class)
        .newInstance(new Bar());

结果为java.lang.IllegalStateException: Cannot call super (or default) method

拦截器有

public void intercept(@Origin Constructor m) {
    System.out.println("Intercepted: " + m.getName());
}

现在它“有效”,虽然我还要弄清楚初始化部分!最终,类Foo现在有了我不想要的构造函数。

但是 - 抱着新闻!

我实验/阅读了一小部分时间并提出了:

    public class Foo {

        public Foo() {
        }

      public String name;
      public Long age;
    }

    FooBar dynamicType = new ByteBuddy(ClassFileVersion.JAVA_V8)
            .subclass(Foo)
            .defineConstructor(PUBLIC)
                    .withParameter(Bar.class)
                    .intercept(MethodCall.(Foo.class.getDeclaredConstructor())
                    .andThen(MethodDelegation.to(new Interceptor())))
            .make()
            .load(getClass().getClassLoader())
            .getLoaded()
            .getConstructor(Bar.class)
            .newInstance(new Bar());


    public void intercept(Bar cls) {
        System.out.println("Intercepted: " + cls);
    }

剩下的就是发现如何获取对intercept()可用的正在构建的实例的引用

2 个答案:

答案 0 :(得分:1)

您的字段是Foo定义的实例字段。如果您定义LoadedTypeInitializer,它将初始化Foo的子类,该子类未声明有问题的两个字段。因此数组是空的。此外,类型初始化程序不会让你到处,因为它用于初始化类型,而不是实例。

您可能想要定义构造函数并从那里设置字段。请记住,任何构造函数都需要首先调用超级构造函数或同一个类的另一个构造函数。 (请查看SuperMethodCall

答案 1 :(得分:1)

经过大约20个小时的试错,基于对相似但最终不同的问题读取40多个不同的“解决方案”,我得出了以下内容,这似乎符合我的意图。

public class Foo {
      public String name;
      public Long age;
    }

public class Bar {
      public String name() {
          return "Name";
      }
      public Long age() {
          return 21;
      }
    }

public class Demo {

    FooBar dynamicType = new ByteBuddy(ClassFileVersion.JAVA_V8)
            .subclass(Foo)
            .defineConstructor(PUBLIC)
                    .withParameter(Bar.class)
                    .intercept(MethodCall.(Foo.class.getDeclaredConstructor())
                    .andThen(MethodDelegation.to(this)))
            .make()
            .load(getClass().getClassLoader())
            .getLoaded()
            .getConstructor(Bar.class)
            .newInstance(new Bar());

    public void intercept(@This Object thiz, @Argument(0) Bar bar) {
        thiz.name = bar.name();
        thiz.age = bar.age();
    }
}

我希望这可以帮助其他一些熬夜油的穷人。