Trader-Demo Flow测试报错KotlinNullPointerException:如何在Flow测试中上传附件?
在Corda Trader-Demo Flow测试中处理附件并解决KotlinNullPointerException
嘿,我刚看到你在Trader-Demo的Flow测试里碰到了KotlinNullPointerException,十有八九是附件相关的初始化或者上传环节出了问题——毕竟在mock测试环境里,Corda不会自动帮你处理附件的存储和分发。我来给你一步步拆解怎么正确在Flow测试中处理附件,帮你搞定这个错误:
为什么会出现这个空指针?
通常这个错误是因为你的Flow代码尝试引用一个未被正确导入的附件,导致AttachmentId为空,或者节点的AttachmentStorage里找不到对应的附件。在真实环境中Corda会处理附件的同步,但mockNet是孤立的测试环境,所有附件都得我们手动管理。
解决步骤:在Flow测试中正确上传并使用附件
1. 创建测试用的附件
你可以用字节数组模拟附件内容,或者从测试资源文件中读取。比如模拟一份商业票据的条款文件:
// 用字节数组模拟附件内容,或者从资源文件读取 val attachmentContent = """ Commercial Paper Terms: - Amount: ${amount.displayString()} - Issue Date: ${Instant.now()} """.trimIndent().toByteArray() val attachmentFileName = "commercial-paper-terms.txt"
2. 将附件导入到节点的AttachmentStorage
mockNet的节点不会自动加载附件,所以必须手动把附件导入到发起节点和所有参与交易的节点的存储中:
// 导入到发起节点(BankCorpNode) BankCorpNode.services.attachmentStorage.importAttachment( inputStream = attachmentContent.inputStream(), filename = attachmentFileName, signers = listOf(BankCorpNode.info.legalIdentity.owningKey) ) // 必须同时导入到接收方节点,否则对方验证交易时会找不到附件 recipient.services.attachmentStorage.importAttachment( inputStream = attachmentContent.inputStream(), filename = attachmentFileName, signers = listOf(BankCorpNode.info.legalIdentity.owningKey) )
这里要注意:signers参数要填附件签名者的公钥,通常就是发起节点的身份公钥,确保交易验证时签名合法。
3. 修改Flow代码,确保正确引用附件
在你的CommercialPaperIssueFlow里,需要从AttachmentStorage中获取附件ID,并添加到交易构建器中:
// 在Flow内部获取附件ID val attachmentQuery = QueryCriteria.AttachmentQueryCriteria(name = attachmentFileName) val attachmentId = serviceHub.attachmentStorage.queryAttachments(attachmentQuery).single().id // 构建交易时添加附件 val txBuilder = TransactionBuilder(notary) .addOutputState(CommercialPaperState(amount, issueRef, ourIdentity, recipient), COMMERCIAL_PAPER_CONTRACT_ID) .addCommand(CommercialPaperContract.Commands.Issue(), ourIdentity.owningKey) .addAttachment(attachmentId) // 关键:把附件添加到交易中
如果这里queryAttachments返回空列表,就会抛出空指针,所以一定要确保附件已经被正确导入。
4. 修改测试代码,整合附件处理逻辑
把上面的步骤整合到你的测试函数中,修改后的代码大概是这样:
private fun issue_commercial_paper( amount: Amount<Currency>, issueRef: OpaqueBytes, recipient: Party, notary: Party, progressTracker: ProgressTracker ): SignedTransaction { // 1. 创建测试附件 val attachmentContent = """ Commercial Paper Terms: - Amount: ${amount.displayString()} - Issue Reference: ${issueRef.toHexString()} """.trimIndent().toByteArray() val attachmentFileName = "cp-terms.txt" // 2. 导入附件到相关节点 BankCorpNode.services.attachmentStorage.importAttachment( attachmentContent.inputStream(), attachmentFileName, listOf(BankCorpNode.info.legalIdentity.owningKey) ) recipient.services.attachmentStorage.importAttachment( attachmentContent.inputStream(), attachmentFileName, listOf(BankCorpNode.info.legalIdentity.owningKey) ) // 3. 启动并运行Flow val p = CommercialPaperIssueFlow(amount, issueRef, recipient, notary, progressTracker) val future = BankCorpNode.services.startFlow(p) mockNet.runNetwork() return future.resultFuture.get() }
5. 排查空指针的小技巧
如果还是碰到空指针,建议:
- 给
queryAttachments的结果加非空判断,比如用singleOrNull()代替single(),然后检查是否为null - 在测试中添加日志或断点,查看
AttachmentStorage中的附件列表,确认附件是否已经被导入 - 检查Flow中是否有其他可能为空的变量,比如
serviceHub或者notary是否被正确初始化
这样处理后,你的Flow测试应该就能正确处理附件,避免空指针错误了。
内容的提问来源于stack exchange,提问作者Chriszer Tamayo
相关产品推荐
相关产品推荐

