这个问题与我之前的问题有关:How to create a default constructor with Byte Buddy
我正在创建一个子类,该子类首先在对某个实例的delegatig方法调用之前设置一些上下文。在剩下一个问题的情况下,这已经可以很好地工作了。
加载动态创建的子类时出现以下错误。
java.lang.VerifyError: Bad access to protected data in invokevirtual
Exception Details:
Location:
com/frequentis/ps/service/test/saga/ProxyTestSaga$ByteBuddy$Rm8DV3Lj.setTimeoutManager(Lcom/codebullets/sagalib/timeout/TimeoutManager;)V @3: invokevirtual
Reason:
Type 'com/frequentis/ps/service/test/saga/ProxyTestSaga' (current frame, stack[0]) is not assignable to 'com/frequentis/ps/service/test/saga/ProxyTestSaga$ByteBuddy$Rm8DV3Lj'
Current Frame:
bci: @3
flags: { }
locals: { 'com/frequentis/ps/service/test/saga/ProxyTestSaga$ByteBuddy$Rm8DV3Lj', 'com/codebullets/sagalib/timeout/TimeoutManager' }
stack: { 'com/frequentis/ps/service/test/saga/ProxyTestSaga' }
Bytecode:
0x0000000: b200 0cb6 0010 57b1
at java.lang.Class.getDeclaredFields0(Native Method)
at java.lang.Class.privateGetDeclaredFields(Class.java:2583)
at java.lang.Class.getDeclaredField(Class.java:2068)
at net.bytebuddy.implementation.LoadedTypeInitializer$ForStaticField.onLoad(LoadedTypeInitializer.java:124)
at net.bytebuddy.implementation.LoadedTypeInitializer$Compound.onLoad(LoadedTypeInitializer.java:200)
at net.bytebuddy.implementation.LoadedTypeInitializer$Compound.onLoad(LoadedTypeInitializer.java:200)
at net.bytebuddy.dynamic.DynamicType$Default$Unloaded.initialize(DynamicType.java:3497)
at net.bytebuddy.dynamic.DynamicType$Default$Unloaded.load(DynamicType.java:3485)
at com.frequentis.ps.service.test.saga.DynamicSagaTypeBuilder.buildAndLoad(DynamicSagaTypeBuilder.java:65)
at com.frequentis.ps.service.test.saga.MoreAbstractSpaceSagaUnitTest.generateProxyClassForSagaUnderTest(MoreAbstractSpaceSagaUnitTest.java:274)
at com.frequentis.ps.service.test.saga.AbstractSpaceSagaUnitTest.enhance(AbstractSpaceSagaUnitTest.java:105)
at com.frequentis.ps.service.test.saga.ProxyTestSagaTest.before(ProxyTestSagaTest.java:27)
当前,这是我的字节伙伴设置,几乎可以在所有情况下使用,但“
setTimeoutManager
”和“ setState
”方法会导致显示的错误。// called within the unit test base class (as shown in the call stack above)
builder = new ByteBuddy()
.subclass(sagaUnderTestClass, ConstructorStrategy.Default.IMITATE_SUPER_TYPE_PUBLIC);
// define default ctor if necessary that passes "null" values to the super ctor
builder.method(isAnnotatedWith(StartsSaga.class).or(isAnnotatedWith(EventHandler.class)))
.intercept(MethodDelegation.to(new ForwardingContextSetupInterceptor<(sagaUnderTest, contextSetter))
.appendParameterBinder(Pipe.Binder.install(Forwarder.class)))
.method(isPublic()
.and(isDeclaredBy(sagaUnderTest.getClass()).or(isDeclaredBy(AbstractSaga.class)
.and(not(isAnnotatedWith(StartsSaga.class))).and(not(isAnnotatedWith(EventHandler.class))))
.intercept(MethodDelegation.to(sagaUnderTest))))
我需要给二传手一个不同的设置吗?
还是由抽象类引起的?
我真的不明白为什么它说对受保护数据的访问不良,这是否意味着私有字段?
我的类型层次结构看起来像这样。声明二传手的最基础类:
public abstract class AbstractSaga<SAGA_STATE extends SagaState> implements Saga<SAGA_STATE>, NeedTimeouts, NeedContext {
private SAGA_STATE state;
private boolean completed;
private TimeoutManager timeoutManager;
private ExecutionContext context;
protected AbstractSaga() {
completed = false;
}
// i have omitted some method for clarity
protected ExecutionContext context() {
return context;
}
@Override
public SAGA_STATE state() {
return state;
}
@Override
public void setState(final SAGA_STATE state) {
this.state = state;
}
@Override
public boolean isFinished() {
return completed;
}
protected void setFinished() {
completed = true;
}
@Override
public void setTimeoutManager(final TimeoutManager timeoutManager) {
this.timeoutManager = timeoutManager;
}
}
扩展者:
public abstract class AbstractSpaceSaga<SAGA_STATE extends SpaceSagaState, MESSAGE extends Message>
extends AbstractSaga<SAGA_STATE> {
}
最后再次扩展为:
public class ProxyTestSaga
extends AbstractSpaceSaga<SpaceSagaState, TestRequest> {
@StartsSaga
public void handle(final TestRequest request) {
}
@EventHandler
public void handle(final TestEvent event) {
}
}
我希望代码是可以理解的,如果需要,我可以添加更多信息。
最佳答案
这绝对是Byte Buddy中的错误,因为它不应允许您创建非法字节码。但是,我对正在发生的事情感到困惑,因为Byte Buddy似乎选择了一种与拦截器不兼容的方法。我只是看了实现,这是不应该发生的。您使用的是最新版本(0.6.14)吗?
拦截器从字节码中生成以下代码:
GETSTATIC (interceptor of type ProxyTestSaga)
INVOKEVIRTUAL (some method without arguments)
POP (drop value of the invoked method)
RETURN
调用委托方法时发生错误。调用为代理类型定义的方法。通过查看Byte Buddy的代码,使用
MethodDelegation
时这是不可能的,因此我假设在某处拾取了另一个拦截器?真正可以帮助我的是一个可以重现该错误的可运行示例。也许您可以分解代码,以便我可以运行它。或者,如果您的应用程序是开源的,也许您可以提供一个指向它的链接,以便我可以运行您的代码。或者,与我联系,以便我可以私下访问您的代码。
最后,您可能想研究
Forwarding
仪器,而不是将MethodDelegation
用于第二次拦截。除此之外,如果您能帮助我修复此错误,我将不胜感激。