クラスの 1 つでいくつかのメソッド呼び出しをインターセプトしたいのですが、それらのクラスにはデフォルトのコンストラクターがありません。
次のクラスが与えられた場合、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
これは正しいアプローチですか?
ここでもバイトバディを使用する必要がありますか、それとももっと簡単な/他の方法がありますか?