我想在我的一个类上拦截一些方法调用,但这些类没有默认的构造函数。
鉴于以下类,我如何设置Byte Buddy也创建一个公共无参数构造函数来创建生成的类?
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
}
}
编辑: 具体用例是简化单元测试设置 目前我们总是要写这样的东西:
@Test
public void someTest() {
// Given
// When
GetLoggedInUsersRequest request = new GetLoggedInUsersRequest();
setMessageForContext(request); // <-- always do this before calling handle
sut.handle(request);
// Then
}
我认为在@Before方法中创建代理会自动为您设置上下文会很好。
@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
}
我玩了一下但不幸的是我没有让它工作..
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();
}
不幸的是现在我得到了(可能是因为ctor调用仍未正确设置)
java.lang.IllegalStateException: Cannot invoke public com.frequentis.ps.account.service.audit.GetLoggedInUsersSaga$ByteBuddy$zSZuwhtR() as a super method
这是否是正确的方法?
我应该在这里使用字节伙伴还是有更容易/其他方式?
答案 0 :(得分:3)
您无法定义没有任何字节代码的构造函数。这将是一个抽象的构造函数,在Java中是非法的。我将为javadoc添加更精确的描述,以用于将来的版本。谢谢你引起我的注意。
您需要定义任何构造函数所需的超级方法调用:
DynamicType.Builder builder = ...
builder = builder
.defineConstructor(Collections.<Class<?>>emptyList(), Visibility.PUBLIC)
.intercept(MethodCall
.invoke(superClass.getDeclaredConstructor())
.onSuper())
至于你应该在这里使用Byte Buddy:我不能用我看到的小代码告诉你。您应该问的问题是:它是否使我的代码更容易,既考虑了代码量又遵循了代码的复杂性?如果Byte Buddy使您的代码更易于使用(并运行),请使用它。如果没有,请不要使用它。