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

yv5phkfx  于 5个月前  发布在  Java
关注(0)|答案(2)|浏览(45)

我一直在广泛地寻找,但没有成功,也找不到答案的例子。
有以下成员的类:

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

字符串
我想构建这个类的一个新实现,它通过委托给一些初始化器类来初始化成员变量。

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()可用的正在构造的示例的引用

t40tm48m

t40tm48m1#

你的字段是由Foo定义的示例字段。如果你定义了一个LoadedTypeInitializer,它将初始化Foo的子类,而这个子类没有声明这两个字段。因此数组是空的。此外,类型初始化器不会让你得到任何东西,因为它是用来初始化类型的,而不是示例。
你可能想定义一个构造函数,并从那里设置字段。记住,任何构造函数都需要首先调用一个超级构造函数或同一个类的另一个构造函数。(看看SuperMethodCall

czfnxgou

czfnxgou2#

经过大约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();
    }
}

字符串
我希望这能帮助一些其他的可怜的灵魂谁一直在熬夜。

相关问题