如何使用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使您的代码更易于使用(并运行),请使用它。 如果没有,请不要使用它。