如何使用Byte Buddy创建默认构造函数 [英] How to create a default constructor with Byte Buddy
问题描述
我想在我的一个类上拦截一些方法调用,但这些类没有默认构造函数。
I want to intercept some method calls on one of my classes but those classes dont have a default constructor.
鉴于以下类,我将如何设置Byte Buddy还要创建一个公共无参构造函数来创建生成的类?
Given the following class, how would I setup Byte Buddy to also create a public no-argument constructor to be able to create the generated class?
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
}
}
编辑:
具体用例是简化单元测试设置。
目前我们总是要写这样的东西:
The concrete use case for this is to simplify unit test setup.
Currently we always have to write something like this:
@Test
public void someTest() {
// Given
// When
GetLoggedInUsersRequest request = new GetLoggedInUsersRequest();
setMessageForContext(request); // <-- always do this before calling handle
sut.handle(request);
// Then
}
我以为会是很高兴在@Before方法中创建代理,自动为您设置上下文。
I thought it would be nice to create a proxy in the @Before method which automatically sets up the context for you.
@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
}
我玩了一下但不幸的是我没有让它运作..
I played around a bit but unfortunately I didnt get it working..
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调用仍未正确设置)
Unfortunately now i get (probably because the ctor invocation is still not correctly setup)
java.lang.IllegalStateException: Cannot invoke public com.frequentis.ps.account.service.audit.GetLoggedInUsersSaga$ByteBuddy$zSZuwhtR() as a super method
这是否是正确的方法?
我应该在这里使用字节伙伴还是更容易/其他方式?
推荐答案
你无法定义没有任何字节代码的构造函数。这将是一个抽象的构造函数,在Java中是非法的。我将为javadoc添加更精确的描述以用于将来的版本。感谢您引起我的注意。
You cannot define a constructor without any byte code. This would be an abstract constructor what is illegal in Java. I am going to add a more precise description to the javadoc for a future version. Thanks for bringing this to my attention.
您需要定义任何构造函数所需的超级方法调用:
You need to define a super method call which is required for any constructor:
DynamicType.Builder builder = ...
builder = builder
.defineConstructor(Collections.<Class<?>>emptyList(), Visibility.PUBLIC)
.intercept(MethodCall
.invoke(superClass.getDeclaredConstructor())
.onSuper())
至于你应该在这里使用Byte Buddy:我不能用我看到的小代码告诉你。您应该问的问题是:它是否使我的代码更容易,既考虑代码量又遵循它的复杂性?如果Byte Buddy使您的代码更易于使用(并运行),请使用它。如果没有,请不要使用它。
As for wheather you should use Byte Buddy here: I cannot tell you from the little code I saw. The question you should ask: Does it make my code easier, both considering the amount of code and the complexity of following it? If Byte Buddy makes your code easier to use (and to run), use it. If not, don't use it.
这篇关于如何使用Byte Buddy创建默认构造函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!