在IntelliJ运行Corda合约Java测试时遇NotSerializableException求助
最近在IntelliJ里跑Corda合约测试时,不少Java开发者会碰到这个头疼的序列化异常:
[ERROR] 17:02:51,821 [main] (Schema.kt:437) amqp.Schema.fingerprintForType - Constructor parameter arg0 doesn't refer to a property of class 'class mypackage.MyState' -> class mypackage.MyState {} java.io.NotSerializableException: Constructor parameter arg0 doesn't refer to a property of class 'class mypackage.MyState' at net.corda.nodeapi.internal.serialization.amqp.SerializationHel...
其实这个问题的核心很简单:Corda的AMQP序列化机制要求状态类的构造函数参数必须和类的成员属性一一对应,并且属性要有可访问的getter方法。序列化器需要通过构造参数找到对应的属性,才能正确完成对象的序列化和反序列化。下面给你几个具体的解决步骤:
核对构造函数与属性的映射关系
先检查你的MyState类,确保构造函数里的每一个参数都对应类里的一个属性,并且这个属性有getter方法。举个正确的例子:public class MyState implements ContractState { // 构造参数对应的成员属性 private final Party issuer; // 构造函数参数直接绑定到属性 public MyState(Party issuer) { this.issuer = issuer; } // 必须提供getter,Corda序列化需要访问这个属性 public Party getIssuer() { return issuer; } // 别忘了实现ContractState要求的getParticipants方法 @Override public List<AbstractParty> getParticipants() { return Arrays.asList(issuer); } }要是你的构造函数里有参数没对应到任何属性,或者属性没有getter,序列化器就会找不到关联关系,直接抛出那个异常。
剔除构造函数里的临时参数
别把一些临时计算用的参数放到构造函数里,比如只是用来初始化其他属性的中间值。这类逻辑应该放在构造函数内部处理,而不是作为构造参数传入。如果必须传,也要确保它对应到类的某个成员属性。排查Lombok注解的问题(如果用了的话)
如果你用了Lombok的@Data、@AllArgsConstructor这类注解来自动生成构造函数和getter,一定要确认注解是否生效。有时候IntelliJ的Lombok插件没配置好,或者编译时注解没正确生成代码,就会导致属性或getter缺失。可以去查看编译后的字节码,或者手动写构造函数和getter来验证。清理项目缓存并重新构建
有时候IntelliJ的缓存或者编译残留会搞出奇怪的问题,试试这几步:- 点击顶部菜单栏的
Build -> Clean Project - 接着执行
Build -> Rebuild Project - 重启IntelliJ后再重新运行测试
- 点击顶部菜单栏的
要是还没解决,你可以手动用Corda的序列化工具类尝试序列化一个MyState实例,这样能更直观地定位到哪个参数或属性出了问题。
内容的提问来源于stack exchange,提问作者Joel

