I want to intercept some method calls on one of my classes, but these classes do not have a default constructor.
Given the following class, how would I configure Byte Buddy to create a public constructor with no arguments in order to be able to create the generated class?
public class GetLoggedInUsersSaga extends AbstractSpaceSingleEventSaga { private final UserSessionRepository userSessionRepository; @Inject public GetLoggedInUsersSaga(final UserSessionRepository userSessionRepository) { this.userSessionRepository = userSessionRepository; } @StartsSaga public void handle(final GetLoggedInUsersRequest request) {
EDIT: A specific use case for this is to simplify unit test setup.
Currently, we always have to write something like this:
@Test public void someTest() {
I thought it would be nice to create a proxy in the @Before method, which automatically sets the context for you.
@Before public void before() { sut = new GetLoggedInUsersSaga(someDependency); sut = intercept(sut); } @Test public void someTest() {
I played a little, but, unfortunately, I did not work.
public <SAGA extends Saga> SAGA intercept(final SAGA sagaUnderTest) throws NoSuchMethodException, IllegalAccessException, InstantiationException { return (SAGA) new ByteBuddy() .subclass(sagaUnderTest.getClass()) .defineConstructor(Collections.<Class<?>>emptyList(), Visibility.PUBLIC) .intercept(MethodCall.invokeSuper()) .method(ElementMatchers.isAnnotatedWith(StartsSaga.class)) .intercept( MethodDelegation.to( new Object() { @RuntimeType public Object intercept( @SuperCall Callable<?> c, @Origin Method m, @AllArguments Object[] a) throws Exception { setMessageForContext((Message) a[0]); return c.call(); } })) .make() .load(getClass().getClassLoader(), ClassLoadingStrategy.Default.WRAPPER) .getLoaded() .newInstance(); }
Unfortunately, now I get (possibly because the ctor call is still not configured correctly)
java.lang.IllegalStateException: Cannot invoke public com.frequentis.ps.account.service.audit.GetLoggedInUsersSaga$ByteBuddy$zSZuwhtR() as a super method
Is this even the right approach?
Should I use bytes here or is there an easier / different way?