简体   繁体   English

如何使用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. 我想拦截我的一个类上的一些方法调用,但这些类没有默认的构造函数。

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? 鉴于以下类,我如何设置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
    }
}

EDIT: 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
}

I thought it would be nice to create a proxy in the @Before method which automatically sets up the context for you. 我认为在@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
}

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();
}

Unfortunately now i get (probably because the ctor invocation is still not correctly setup) 不幸的是现在我得到了(可能是因为ctor调用仍未正确设置)

java.lang.IllegalStateException: Cannot invoke public com.frequentis.ps.account.service.audit.GetLoggedInUsersSaga$ByteBuddy$zSZuwhtR() as a super method

Is this even the correct approach? 这甚至是正确的方法吗?
Should I even use byte buddy here or is there an easier/other way? 我应该在这里使用字节伙伴还是更容易/其他方式?

You cannot define a constructor without any byte code. 您无法定义没有任何字节代码的构造函数。 This would be an abstract constructor what is illegal in Java. 这将是一个抽象的构造函数,在Java中是非法的。 I am going to add a more precise description to the javadoc for a future version. 我将为javadoc添加更精确的描述,以用于将来的版本。 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())

As for wheather you should use Byte Buddy here: I cannot tell you from the little code I saw. 至于你应该在这里使用Byte Buddy:我不能用我看到的小代码告诉你。 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. 如果Byte Buddy使您的代码更易于使用(并运行),请使用它。 If not, don't use it. 如果没有,请不要使用它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM