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

问题描述 投票:0回答:2

我进行了广泛的搜索,但没有成功,并且在示例中找不到答案。

与以下成员一起上课:

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()

使用
java byte-buddy
2个回答
1
投票

您的字段是由

Foo
定义的实例字段。如果您定义
LoadedTypeInitializer
,它将初始化
Foo
的子类,该子类不会声明相关的两个字段。因此数组为空。此外,类型初始值设定项不会带您到任何地方,因为它用于初始化类型,而不是实例。

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

SuperMethodCall
即可了解。


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.invoke(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();
    }
}

我希望这能帮助其他一些熬夜的可怜人。

© www.soinside.com 2019 - 2024. All rights reserved.