I am using byte-buddy to build an ORM on top of Ignite, we need to add a field to a class and then access it in a method interceptor..
So here's an example where I add a field to a class
final ByteBuddy buddy = new ByteBuddy();
final Class<? extends TestDataEnh> clz = buddy.subclass(TestDataEnh.class)
.defineField("stringVal",String.class)
.method(named("setFieldVal")).intercept(
MethodDelegation.to(new SetterInterceptor())
)
.make()
.load(getClass().getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
.getLoaded();
final TestDataEnh enh = clz.newInstance();
enh.getFieldVal();
enh.setFieldVal();
System.out.println(enh.getClass().getName());
And the Interceptor is like this
public class SetterInterceptor {
@RuntimeType
public Object intercept() {
System.out.println("Invoked method with: ");
return null;
}
}
So how do I get the value of the new field into the interceptor so I can change it's value? (stringVal)
Thanks in advance
You can use a FieldProxy
to access a field by its name. You need to install a FieldProxy.Binder
and register it on the MethodDdelegation
before you can use it as it requires a custom type for type-safe instrumentation. The javadoc explains how this can be done. Alternatively, you can use reflection on an instance by using @This
. The JVM is quite efficient in optimizing the use of reflection.
An example would be:
interface FieldGetter {
Object getValue();
}
interface FieldSetter {
void setValue(Object value);
}
public class SetterInterceptor {
@RuntimeType
public Object intercept(@FieldProxy("stringVal") FieldGetter accessor) {
Object value = accessor.getValue();
System.out.println("Invoked method with: " + value);
return value;
}
}
For bean properties, the FieldProxy
annotation does not require an explicit name but discovers the name from the name of the intercepted getter or setter.
The installation can be done as follows:
MethodDelegation.to(SetterInterceptor.class)
.appendParameterBinder(FieldProxy.Binder.install(FieldGetter.class,
FieldSetter.class));