Cómo crear un constructor predeterminado con Byte Buddy
Quiero interceptar algunas llamadas a métodos en una de mis clases, pero esas clases no tienen un constructor predeterminado.
Dada la siguiente clase, ¿cómo configuraría Byte Buddy para crear también un constructor público sin argumentos para poder crear la clase generada?
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) {
// this is the method in want to intercept
}
}
EDITAR: El caso de uso concreto para esto es simplificar la configuración de la prueba unitaria.
Actualmente siempre tenemos que escribir algo como esto:
@Test
public void someTest() {
// Given
// When
GetLoggedInUsersRequest request = new GetLoggedInUsersRequest();
setMessageForContext(request); // <-- always do this before calling handle
sut.handle(request);
// Then
}
Pensé que sería bueno crear un proxy en el método @Before que configura automáticamente el contexto para usted.
@Before
public void before() {
sut = new GetLoggedInUsersSaga(someDependency);
sut = intercept(sut);
}
@Test
public void someTest() {
// Given
// When
GetLoggedInUsersRequest request = new GetLoggedInUsersRequest();
sut.handle(request);
// Then
}
Jugué un poco, pero desafortunadamente no pude hacerlo funcionar ...
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();
}
Desafortunadamente, ahora obtengo (probablemente porque la invocación de ctor todavía no está configurada correctamente)
java.lang.IllegalStateException: Cannot invoke public com.frequentis.ps.account.service.audit.GetLoggedInUsersSaga$ByteBuddy$zSZuwhtR() as a super method
¿Es este incluso el enfoque correcto?
¿Debería usar byte buddy aquí o hay alguna otra manera más fácil?