如何使用Byte Buddy创建默认构造函数
我想拦截我的一个类上的一些方法调用,但这些类没有默认的构造函数。
鉴于以下类,我如何设置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 } }
编辑:具体的用例是简化unit testing设置。
目前我们总是要写这样的东西:
@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 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
这甚至是正确的方法吗?
我应该在这里使用字节伙伴还是更容易/其他方式?
您无法定义没有任何字节代码的构造函数。 这将是一个抽象的构造函数,在Java中是非法的。 我将为javadoc添加更精确的描述以用于将来的版本。 谢谢你引起我的注意。
您需要定义任何构造函数所需的超级方法调用:
DynamicType.Builder builder = ... builder = builder .defineConstructor(Collections.>emptyList(), Visibility.PUBLIC) .intercept(MethodCall .invoke(superClass.getDeclaredConstructor()) .onSuper())
至于你应该在这里使用Byte Buddy:我不能用我看到的小代码告诉你。 您应该问的问题是:它是否使我的代码更容易,既考虑代码量又遵循它的复杂性? 如果Byte Buddy使您的代码更易于使用(并运行),请使用它。 如果没有,请不要使用它。