在抽象基础 class 上委派给 setter 导致加载时出现 VerifyError
Delegation to setter on abstract base class results in VerifyError on load
这个问题与我之前在这里的问题有关:How to create a default constructor with Byte Buddy
我正在创建一个子class,它在委托方法调用到某个实例之前首先设置一些上下文。这已经很好地解决了一个问题。
加载动态创建的子程序时出现以下错误class。
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))))
二传手需要不同的设置吗?
还是抽象造成的class?
不太明白为什么说bad access to protected data,是私有域的意思吗?
我的类型层次结构如下所示。声明设置器的最顶层 class:
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
时这是不可能的,所以我假设另一个拦截器在某处被拾取?
真正能帮助我的是 运行 重现错误的可行示例。也许你可以分解你的代码,这样我就可以 运行 它了。或者,如果您的应用程序是开源的,也许您可以向它提供一个 link,这样我就可以 运行 您的代码。或者,与我联系,以便我可以私下访问您的代码。
最后,您可能想查看 Forwarding
工具而不是使用 MethodDelegation
进行第二次拦截。 Beyond,如果你能帮我修复这个bug,我将不胜感激。
嗯,您提供的示例有很多问题,这肯定会使事情变得糟糕。
我觉得您可能应该更好地研究抽象 classes,如何使用它们以及为什么使用它们。
摘要 class 可以用作子class 启动的蓝图。它也可以用作 classes 的中央库,以获取通用字段和方法。摘要 classes 只能包含原始 m 方法。摘要从不初始化。如果你需要它来初始化你必须 subclass 它,并且 subclass 不能初始化,除非它在父抽象 class 中实现所有的 aqbstract 方法。据我所知,您没有在任何一个扩展中初始化您的方法,因此 class 中的 none 每个都变成了一个对象。您可以将 getter 和 setter 放在那里,但它们无法获取或设置任何东西,直到 class 的某些扩展最终完成打开所有内容并成为对象的完整实例。在你做某事之前,它有点像一个内置的图书馆。我用它来保存一个包可能会用到的许多常见的东西,这样我就可以一遍又一遍地抓住它们,并在包的其他地方有更简单的 classes。
总而言之,你的 class ProxyTestSaga 没有初始化,而且必须是抽象的,因为它扩展了抽象 class AbstractSpace saga 并且没有初始化它所有的继承方法,你没有在 ProxyTestSage 做完。
我几乎不敢回答这个问题,因为您编辑了一些代码。但是,我相信您的修订注释意味着原始摘要中有更多代码从未被初始化。当它到达摘要的最终扩展时,就会发生错误。
现在长风已经过去了,我看到你在那里声明了覆盖,它们看起来像是要覆盖并为你加载的 classes 提供一些可访问性 classes.
您应该可以通过完成所有初始化来解决您的问题。
但是我看到其他一些事情让我相信你用错了。看来您正试图从其他几个 classes 中保留一组方法,以便稍后从一个点使用。这不是抽象的目的。您使用一个界面来创建许多面向外的方法的中央存储库。
简而言之,您可以使用一个接口来实现多个方法,获取这些方法,然后其他 classes 可以使用您的接口获取并覆盖它们以达到他们的目的。
另一件事让我相信你用错了东西。 Abstract classes只能初始化1个class。接口不是 classes,可以扩展多个 classes。所以这是你的代码的另一件事。我真的不知道为什么你的 IDE 没有对你尖叫。
您应该花几个小时深入阅读接口和抽象及其规则。它们各有特点和优点,如果使用得当,都是很好的工具。
这个问题与我之前在这里的问题有关:How to create a default constructor with Byte Buddy
我正在创建一个子class,它在委托方法调用到某个实例之前首先设置一些上下文。这已经很好地解决了一个问题。
加载动态创建的子程序时出现以下错误class。
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))))
二传手需要不同的设置吗?
还是抽象造成的class?
不太明白为什么说bad access to protected data,是私有域的意思吗?
我的类型层次结构如下所示。声明设置器的最顶层 class:
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
时这是不可能的,所以我假设另一个拦截器在某处被拾取?
真正能帮助我的是 运行 重现错误的可行示例。也许你可以分解你的代码,这样我就可以 运行 它了。或者,如果您的应用程序是开源的,也许您可以向它提供一个 link,这样我就可以 运行 您的代码。或者,与我联系,以便我可以私下访问您的代码。
最后,您可能想查看 Forwarding
工具而不是使用 MethodDelegation
进行第二次拦截。 Beyond,如果你能帮我修复这个bug,我将不胜感激。
嗯,您提供的示例有很多问题,这肯定会使事情变得糟糕。
我觉得您可能应该更好地研究抽象 classes,如何使用它们以及为什么使用它们。
摘要 class 可以用作子class 启动的蓝图。它也可以用作 classes 的中央库,以获取通用字段和方法。摘要 classes 只能包含原始 m 方法。摘要从不初始化。如果你需要它来初始化你必须 subclass 它,并且 subclass 不能初始化,除非它在父抽象 class 中实现所有的 aqbstract 方法。据我所知,您没有在任何一个扩展中初始化您的方法,因此 class 中的 none 每个都变成了一个对象。您可以将 getter 和 setter 放在那里,但它们无法获取或设置任何东西,直到 class 的某些扩展最终完成打开所有内容并成为对象的完整实例。在你做某事之前,它有点像一个内置的图书馆。我用它来保存一个包可能会用到的许多常见的东西,这样我就可以一遍又一遍地抓住它们,并在包的其他地方有更简单的 classes。
总而言之,你的 class ProxyTestSaga 没有初始化,而且必须是抽象的,因为它扩展了抽象 class AbstractSpace saga 并且没有初始化它所有的继承方法,你没有在 ProxyTestSage 做完。
我几乎不敢回答这个问题,因为您编辑了一些代码。但是,我相信您的修订注释意味着原始摘要中有更多代码从未被初始化。当它到达摘要的最终扩展时,就会发生错误。
现在长风已经过去了,我看到你在那里声明了覆盖,它们看起来像是要覆盖并为你加载的 classes 提供一些可访问性 classes.
您应该可以通过完成所有初始化来解决您的问题。
但是我看到其他一些事情让我相信你用错了。看来您正试图从其他几个 classes 中保留一组方法,以便稍后从一个点使用。这不是抽象的目的。您使用一个界面来创建许多面向外的方法的中央存储库。
简而言之,您可以使用一个接口来实现多个方法,获取这些方法,然后其他 classes 可以使用您的接口获取并覆盖它们以达到他们的目的。
另一件事让我相信你用错了东西。 Abstract classes只能初始化1个class。接口不是 classes,可以扩展多个 classes。所以这是你的代码的另一件事。我真的不知道为什么你的 IDE 没有对你尖叫。
您应该花几个小时深入阅读接口和抽象及其规则。它们各有特点和优点,如果使用得当,都是很好的工具。