I'd like to add the following code to existing classes using ByteBuddy. Given an existing class SomeSample
I want to turn this into the follwoing:
class SomeSample {
private @Transient boolean isNew = true;
public boolean isNew() {
return isNew;
}
@PrePersist
@PostLoad
void markNotNew() {
this.isNew = false;
}
}
I can get the field and methods added properly. What I cannot really get to work is the assignment of the value. I've learned that I need to augment all existing constructors of the class I want to augment as technically an assignment declared like this is compiled into the constructors.
I've created the following helper:
public class Helper {
@OnMethodExit
public static void initField(@FieldValue(value = "isNew", readOnly = false) boolean value) {
value = !value;
}
}
and tried to assign this as follows:
builder.constructor(ElementMatchers.any())
.intercept(Advice.to(Helper.class));
I would've expected the advice to be added at the end of the original declarations but during the build I receive the following error:
Failed to transform class files in …: Cannot call super (or default) method for public ….SomeSample()
Instead of flipping the value of the field I thought I could also stay with the default (false
) and negate the value returned from the generated isNew()
method. If I change my helper to this:
public class Helper {
public static boolean isNew(@FieldValue(value = "isNew") boolean value) {
return !value;
}
}
When I change my method generating code for isNew()
to the following:
builder = builder.defineMethod("isNew", boolean.class, Visibility.PUBLIC)
.intercept(MethodDelegation.to(Helper.class));
I get:
None of [public static boolean ….Helper.isNew(boolean)] allows for delegation from public boolean SomeSample.isNew()
Any idea?
That was maybe an unfortunate API choice but you can use Advice
both as decorator and interceptor. What you likely would want to would be to set:
builder = builder.visit(Advice.to(Helper.class).on(isConstructor()))
This adds the code around the existing code. With the suggested approach, you replace the method around a call to the original implementation. If you define a new method, such an implementation does not exist and the error you are seeing is yielded.