6

我想拦截我的一个类上的一些方法调用,但这些类没有默认构造函数。

给定以下类,我将如何设置 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

这甚至是正确的方法吗?
我应该在这里使用字节伙伴还是有更简单/其他的方式?

4

1 回答 1

2

您不能定义没有任何字节码的构造函数。这将是一个抽象构造函数,在 Java 中是非法的。我将为将来的版本向 javadoc 添加更精确的描述。感谢您引起我的注意。

您需要定义任何构造函数都需要的超级方法调用:

DynamicType.Builder builder = ...
builder = builder
  .defineConstructor(Collections.<Class<?>>emptyList(), Visibility.PUBLIC)
  .intercept(MethodCall
               .invoke(superClass.getDeclaredConstructor())
               .onSuper())

至于你是否应该在这里使用 Byte Buddy:我无法从我看到的小代码中告诉你。你应该问的问题:考虑到代码的数量和遵循它的复杂性,它是否让我的代码更容易?如果 Byte Buddy 使您的代码更易于使用(和运行),请使用它。如果没有,请不要使用它。

于 2015-07-07T13:30:50.073 回答