如何让 ByteBuddy 构建 class 实现并初始化成员变量?
How can I get ByteBuddy to build a class implementation and initialise the member variables?
我一直在广泛搜索但没有成功,并且在示例中找不到答案。
与以下成员有一个 class:
public class Foo {
public String name;
public Long age;
}
我想构建这个 class 的新实现,它通过委托给一些 initliaiser class.
来初始化成员变量
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());
}
现在是'works',虽然我还没有弄清楚初始化部分!最终,class Foo
现在有了我不想要的构造函数。
但是 - 按住按钮!
我experimented/read进入凌晨,想出了:
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()
使用
您的字段是由 Foo
定义的实例字段。如果您定义了一个 LoadedTypeInitializer
,它将初始化 Foo
的子 class,它没有声明这两个有问题的字段。因此数组为空。此外,类型初始值设定项不会带您到任何地方,因为它用于初始化类型,而不是实例。
您可能想要定义一个构造函数并从那里设置字段。请记住,任何构造函数都需要首先调用同一 class 的超级构造函数或另一个构造函数。 (为此请查看 SuperMethodCall
。
经过大约 20 个小时的 trial-and-error 阅读 40 多个不同的 'solutions' 到类似但最终不同的问题,我得出了以下结论,这似乎符合我的意图。
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();
}
}
我希望这对其他一直在挑灯夜战的可怜人有所帮助。
我一直在广泛搜索但没有成功,并且在示例中找不到答案。
与以下成员有一个 class:
public class Foo {
public String name;
public Long age;
}
我想构建这个 class 的新实现,它通过委托给一些 initliaiser class.
来初始化成员变量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());
}
现在是'works',虽然我还没有弄清楚初始化部分!最终,class Foo
现在有了我不想要的构造函数。
但是 - 按住按钮!
我experimented/read进入凌晨,想出了:
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()
您的字段是由 Foo
定义的实例字段。如果您定义了一个 LoadedTypeInitializer
,它将初始化 Foo
的子 class,它没有声明这两个有问题的字段。因此数组为空。此外,类型初始值设定项不会带您到任何地方,因为它用于初始化类型,而不是实例。
您可能想要定义一个构造函数并从那里设置字段。请记住,任何构造函数都需要首先调用同一 class 的超级构造函数或另一个构造函数。 (为此请查看 SuperMethodCall
。
经过大约 20 个小时的 trial-and-error 阅读 40 多个不同的 'solutions' 到类似但最终不同的问题,我得出了以下结论,这似乎符合我的意图。
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();
}
}
我希望这对其他一直在挑灯夜战的可怜人有所帮助。