如何使用Byte Buddy创建默认构造函数 [英] How to create a default constructor with Byte Buddy

查看:274
本文介绍了如何使用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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆