I have been searching extensively without success, and can't find the answer in the examples.
Having a class with the following members:
public class Foo {
public String name;
public Long age;
}
I want to build a new implementation of this class that initialises the member variables by delegating to some initliaiser class.
Bar dynamicType = new ByteBuddy(ClassFileVersion.JAVA_V8)
.subclass(Foo)
.initializer(new BarInit())
.make()
.load(Foo.class.getClassLoader(), WRAPPER)
.getLoaded()
.newInstance();
also created
public class BarInit implements LoadedTypeInitializer {
@Override
public void onLoad(Class<?> type) {
Field[] fields = type.getDeclaredFields();
// fields is empty?!
}
@Override
public boolean isAlive() {
return true;
}
}
I think I've gone code-blind. I need a hint.
So after some hints I moved on to
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());
results in java.lang.IllegalStateException: Cannot call super (or default) method
The interceptor has
public void intercept(@Origin Constructor m) {
System.out.println("Intercepted: " + m.getName());
}
and now it 'works', although I'm still to figure out the initialisation part! And ultimately, the class Foo
now has constructors I didn't want.
But - HOLD THE PRESS!
I experimented/read into the small hours and came up with:
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);
}
What remains is to discover how to get a reference to the instance being constructed being made available to intercept()
After some 20 hours of trial-and-error based on reading 40+ different 'solutions' to similar - but ultimately different - problems, I arrived at the following, which seems to do what I intended.
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();
}
}
I hope this helps some other poor soul who has been burning the midnight oil.