从外部CorDapp扩展和覆盖流

Corda 4于上周(2月21日)发布,带来了大量的新功能,使Corda的使用更加愉快。 老实说,我有点假设有很多新功能。 我快速浏览了变更日志,主要是看到我的贡献被引用,但是我记得看到很多文本行。 那一定是一件好事吧?

无论如何,这些功能之一就是能够扩展和覆盖流程。 当您意识到Corda用Kotlin编写并完全继承了继承性时,听起来并不是很花哨(对于Java也是如此)。 但是,不仅如此。 Corda需要将“启动流”映射到与其响应的交易对手流。

当两方使用相同的CorDapp时,这很好。 在这种情况下,不会增加任何额外的复杂性。 另一方面,如果交易对手希望在收到交易后将一些数据发送到外部系统,他们该怎么做? 原始的CorDapp不了解或不关心此系统,因此无法满足这些需求。 能够解决这类问题,开发人员可以在现有的CorDapps的基础上构建并对其进行调整,使其更适合其用例。 此外,一旦制定了良好的实践,扩展第三方CorDapps将变得更加容易,并且在其他人已经解决了部分问题的情况下,不再需要开发团队不断重新发明轮子。 显然,这假定可以访问这些外部CorDapp,但这完全是可能的。 特别是在R3 Marketplace已经展示了一个集合的情况下。

在本文中,我们将专注于扩展和覆盖流程。 此外,我们将采用两种不同观点的观点。

  • CorDapp的开发人员/维护人员
  • 想要使用和改编现有CorDapp的开发人员

为了使该过程正常进行,双方都必须努力以适当的方式编写其应用程序,以便可以利用这些好处。

我们将首先查看原始CorDapp必须包含的内容,然后是开发人员必须进行扩展的内容。

在继续之前,这里有指向扩展和覆盖流程的官方文档的链接。

编写基本流程以允许扩展

以一种易于扩展的方式编写CorDapp可能需要进行大量思考。 这在很大程度上取决于CorDapp维护人员要实现的目标。 为开发人员提供一种扩展CorDapp的方法,以便他们可以将数据发送到外部系统或添加自己的日志记录,这不会造成任何问题。 另一方面,允许更改事务的内容或将事务的内容发送给谁将需要更多的考虑以确保不会滥用CorDapp。 我希望在以后的帖子中进一步探讨这个主题。

出于本文的目的,我们将介绍更简单的选项。 让我们直接进入,因为到目前为止有很多文本,没有代码。 以下是将充当“基本”流程的SendMessageFlow ,它将在后面的部分中进行扩展:

@InitiatingFlow
open class SendMessageFlow(private val message: MessageState) :FlowLogic<SignedTransaction>() {open fun preTransactionBuild() {// to be implemented by sub type flows - otherwise do nothing}open fun preSignaturesCollected(transaction: SignedTransaction) {// to be implemented by sub type flows - otherwise do nothing}open fun postSignaturesCollected(transaction: SignedTransaction) {// to be implemented by sub type flows - otherwise do nothing}open fun postTransactionCommitted(transaction: SignedTransaction) {// to be implemented by sub type flows - otherwise do nothing}@Suspendablefinal override fun call(): SignedTransaction {logger.info("Started sending message ${message.contents}")preTransactionBuild()val tx = verifyAndSign(transaction())preSignaturesCollected(tx)val sessions = listOf(initiateFlow(message.recipient))val stx = collectSignature(tx, sessions)postSignaturesCollected(stx)return subFlow(FinalityFlow(stx, sessions)).also {logger.info("Finished sending message ${message.contents}")postTransactionCommitted(it)}}// collectSignature// verifyAndSign// transaction
}

我删除了一些功能,因此我们可以专注于重要的事情。

允许扩展此类的第一步甚至有时很重要的步骤是它是open 。 这更多的是Kotlin,而不是Java,因为Kotlin中的所有类默认都是final 。 如果您使用Java编写此代码,则只需忽略最后几句话!

接下来,有一系列可以被覆盖的功能。 每个功能已放置在Flow主要执行程序内的适当位置。 Flow运行时将调用它们。 目前,由于没有为CorDapp开发人员提供任何使用,因此为他们提供了空的实现。

关于open功能。 您可以命名它们或将它们放置在任何需要的位置。 我认为这些功能对于希望在基本应用程序提供的内容上增加额外可追溯性的开发人员很有用。

深入了解更多细节。 call函数已经final (与Java中相同),以防止覆盖Flow的全部内容。 如果有人想采用您的Flow并完全取代其“主要”功能,那有什么意义呢? 对我来说,这似乎有点狡猾。 消除这种可能性使其final成为明智之举。

稍后,我们将研究如何将此Flow子类化。

下面是与SendMessageResponder交互的SendMessageFlow 。 它遵循与上述相同的概念,因此在以后我仅将其显示为参考:

@InitiatedBy(SendMessageFlow::class)
open class SendMessageResponder(private val session: FlowSession) : FlowLogic<Unit>() {open fun postTransactionSigned(transaction: SignedTransaction) {// to be implemented by sub type flows - otherwise do nothing}open fun postTransactionCommitted(transaction: SignedTransaction) {// to be implemented by sub type flows - otherwise do nothing}@Suspendablefinal override fun call() {val stx = subFlow(object : SignTransactionFlow(session) {override fun checkTransaction(stx: SignedTransaction) {}})postTransactionSigned(stx)val committed = subFlow(ReceiveFinalityFlow(otherSideSession = session,expectedTxId = stx.id))postTransactionCommitted(committed)}
}

扩展现有的启动流

在本节中,我们将看到开发人员如何利用在上一个Flow上完成的工作。 它已经具有所有必需的功能。 唯一缺少的是开发人员想要添加的少量额外的可追溯性。这要归功于基本Flow所添加的功能。 这不会造成任何问题。

让我们从扩展启动流开始。 这样做的要求如下:

  • 扩展基础@InitiatingFlow
  • 不要添加@InitiatingFlow到新的流程(错误会发生,如果你这样做)
  • 引用基本Flow的构造函数(Java中的super
  • 覆盖任何所需的功能
  • 调用新流程而不是基本流程

阅读该列表后,您可能已经意识到,这几乎是对面向对象语言(例如Kotlin和Java)中继承的描述。 Corda内可能还有更多事情要做,但是从您的角度来看,您只是像往常一样编写普通的面向对象的代码。

遵循这些要求,我们可以看到扩展Flow的外观:

@StartableByRPC
class CassandraSendMessageFlow(private val message: MessageState) :SendMessageFlow(message) {override fun preTransactionBuild() {serviceHub.cordaService(MessageRepository::class.java).save(message,sender = true,committed = false)logger.info("Starting transaction for message: $message")}override fun preSignaturesCollected(transaction: SignedTransaction) {val keys = transaction.requiredSigningKeys - ourIdentity.owningKeylogger.info("Collecting signatures from $keys for transaction for message: $message")}override fun postSignaturesCollected(transaction: SignedTransaction) {logger.info("Collected signatures for transaction for message: $message")}override fun postTransactionCommitted(transaction: SignedTransaction) {serviceHub.cordaService(MessageRepository::class.java).save(message,sender = true,committed = true)logger.info("Committed transaction for message: $message")}
}

我留下了实现我所谈论的额外可追溯性的所有嘈杂函数,但这是由于没有它们的类将有多么空。 由于不需要call 。 此流程仅需要覆盖open功能。 老实说,根本不需要覆盖它们,它们是可选的。 如果需要,此流可以覆盖单个函数,然后将其保留为空。

是否满足上述所有要求?

  • CassandraSendMessageFlow扩展了SendMessageFlow
  • 看不到@InitiatingFlow
  • 在Kotlin中,无论如何都必须调用super构造函数,这样就完成了
  • 在这种情况下,所有功能都被覆盖
  • 我们还没有走这么远

好的,到目前为止是4/5。 那是一个很好的开始。 要划掉列表中的最后一项,我们需要查看其调用方式。 以下是调用基本SendMessageFlowCassandraSendMessageFlow扩展Flow的代码片段。

SendMessageFlow开始:

proxy.startFlow(::SendMessageFlow, messageState)

其次是CassandraSendMessageFlow

proxy.startFlow(::CassandraSendMessageFlow, messageState)

注意区别吗? 在这种情况下,仅流的名称已更改。 没有其他的。

这两个片段都是完全有效的。 仍然允许调用原始的SendMessageFlow 。 请记住,从我们的角度来看,它只是普通的面向对象代码。 它不会将多余的代码添加到扩展的Flow中,但是它仍然可以执行而不会出现问题。 完成此步骤符合扩展@InitiatingFlow的最后要求。

在结束本节之前,这里是Corda文档中需要记住的重要信息:

“您必须确保子类中的发送/接收/子流的顺序与父类兼容。”

我将把它放在以下所有部分中,因为不遵循这将导致您的流程失败。

扩展响应者流程

扩展响应者流的方式与扩展@InitiatingFlow流的方式非常相似。 唯一的区别是它的调用方式。 如文档中所述:

“ Corda会检测到 BaseResponder SubResponder 都已配置为响应发起方。 然后,Corda将计算到 FlowLogic 的跃点, 并选择距离最远的实现,即:子类化最多的实现。”

“最子类化”的陈述是本文的重要内容。 因此,从开发人员的角度来看,他们所需要做的就是扩展外部基本“响应者流程”,仅此而已。 我非常喜欢之前的需求列表,因此让我们再看一遍扩展响应者流程:

  • 扩展基础@InitiatedBy /响应者流
  • @InitiatedBy添加到新流程
  • 引用基本Flow的构造函数(Java中的super
  • 覆盖任何所需的功能

如果您保持警惕,您可能已经注意到,没有提到如何调用它。 扩展的“响应者流”不需要在其他任何地方调用或引用。 Corda将尽一切努力将所有物品路由到正确的位置。

可以肯定的是,让我们快速看一个例子:

@InitiatedBy(SendMessageFlow::class)
class CassandraSendMessageResponder(session: FlowSession) :SendMessageResponder(session) {override fun postTransactionSigned(transaction: SignedTransaction) {val message = transaction.coreTransaction.outputsOfType<MessageState>().single()logger.info("Signed transaction for message: $message")}override fun postTransactionCommitted(transaction: SignedTransaction) {val message = transaction.coreTransaction.outputsOfType<MessageState>().single()serviceHub.cordaService(MessageRepository::class.java).save(message,sender = false,committed = true)logger.info("Committed transaction for message: $message")}
}

此外,让我们再次回顾“最子类化”的说法。 CassandraSendMessageResponderSendMessageResponder的子类,因此由Corda选择以处理来自发起流的请求。 但是,这可以采取进一步的措施。 如果还有另一个类,例如说SuperSpecialCassandraSendMessageResponder ,那么此流程现在就是Corda将开始使用的流程。 尽管我确实发现这种情况目前不太可能,但绝对值得了解。

再次复制并粘贴此语句,这样您就不会忘记:

“您必须确保子类中的发送/接收/子流的顺序与父类兼容。”

覆盖响应者流程

这是故意的一个单独的部分。 在这里,我们将专门讨论覆盖响应程序流而不是扩展响应流。 您为什么要这样做,有什么区别? 回答第一个问题,开发人员可能想要编写一个与原始基础流程有很大差异的“响应者流程”,但仍需要与外部CorDapp提供的特定“启动流程”进行交互。 为此,他们可以覆盖Flow。 另一个描述这个的词可以是“替换”。 原始基本流程已完全被替代流程取代。 在这种情况下不涉及扩展。

我认为Corda文档在此主题上的措辞非常好:

“虽然子类化方法可能对大多数应用程序有用,但还有另一种机制可以覆盖这种行为。 例如,如果特定的CordApp用户需要这样一个不同的响应者,则将现有流子类化不是一个好的解决方案,这将很有用。”

希望此摘录以及我之前的描述将阐明扩展和覆盖响应程序流之间的区别。

那么,最重要的Flow会是什么样子? 好吧,在合理范围内,您真正想要的任何东西。 也许看起来像下面,尽管我对此表示怀疑:

@InitiatedBy(SendMessageFlow::class)
class OverridingResponder(private val session: FlowSession) :FlowLogic<Unit>() {@Suspendableoverride fun call() {val stx = subFlow(object : SignTransactionFlow(session) {override fun checkTransaction(stx: SignedTransaction) {}})logger.info("Screw the original responder. I'll build my own responder... with blackjack and hookers!")subFlow(ReceiveFinalityFlow(otherSideSession = session,expectedTxId = stx.id))}
}

由于此流程完全替代了原始基本流程,因此它看起来就像普通的响应者流程。 既然如此,那是一个。 这意味着它有@InitiatedBy引用了Initiating Flow,扩展了FlowLogic并实现了call函数。

最后一次将它放在这里:

“您必须确保子类中的发送/接收/子流的顺序与父类兼容。”

在这里,这比前几节更为普遍。 由于整个call函数都已被覆盖,因此您必须确保每个sendreceive都在正确的位置,以便与启动流的交互不会出现错误。

在配置方面,要做更多的事情,而不是扩展Flow。 在这种情况下,我们正在尝试将响应者完全替换为另一个。 为此,我们需要一种方法来告诉节点将交互从“发起流”重定向到新的优先响应器流。 Corda提供了一种做到这一点的方法。

要指定重定向,请将以下内容添加到您的node.conf

flowOverrides {overrides=[{initiator="com.lankydanblog.tutorial.base.flows.SendMessageFlow"responder="com.lankydanblog.tutorial.cassandra.flows.OverridingResponder"}]
}

显然,更改您自己引用的类…

那么这是怎么回事? 这个配置说, SendMessageFlow通常与之交互SendMessageResponder现在将路线OverridingResponder代替。

为了使一切都变得简单, Cordform插件提供了flowOverride方法作为deployNodes一部分。 然后,将为您生成上面的配置块。 对于上面的示例,使用了以下代码:

node {name "O=PartyA,L=London,C=GB"p2pPort 10002rpcSettings {address("localhost:10006")adminAddress("localhost:10046")}rpcUsers = [[user: "user1", "password": "test", "permissions": ["ALL"]]]cordapp(project(':cordapp-contracts-states'))cordapp(project(':cordapp'))cordapp(project(':cordapp-extended-cassandra'))// the important partflowOverride("com.lankydanblog.tutorial.base.flows.SendMessageFlow","com.lankydanblog.tutorial.cassandra.flows.OverridingResponder")
}

现在,在deployNodes运行并启动了节点之后,来自SendMessageFlow或其任何子类的任何请求现在都将通信路由到OverridingResponder

结论

Corda 4提供的便捷功能之一就是能够从第三方CorDapps(或您自己的)自定义Flow。 这可以通过扩展或覆盖两种方法来完成。

扩展将是我在这两者之间的第一选择,但确实需要CorDapp开发人员付出更多的努力。 他们必须提供足够的自定义渠道,而不放弃对Flows原始功能的控制。 提供很少的自定义可能不会阻止其他开发人员使用他们的CorDapp。 但是,开发人员可能会对缺乏对自己的应用程序的控制感到不满。 这是一个湿滑的坡道,可通过自定义路线来控制原始意图。 另一方面,实际上扩展Flow并不需要太多工作,这使开发人员更容易采用和适应外部Flow。

另一方面,对于CorDapp开发人员而言,覆盖不需要任何工作,而是可以利用外部响应程序流将所有内容放到开发人员中。 那是因为现有的Flow几乎被丢弃了,并且回溯到原始实现的唯一参考就是指向Initiating Flow的链接。

通过同时支持Flow的扩展和覆盖,CorDapp开发人员将能够利用外部CorDapp,同时仍提供足够的自定义功能来满足他们可能拥有的所有业务需求。 随着时间的流逝,开发人员将推动重用现有CorDapps的使用,因为它们提供了对其他自定义项的访问权限,很快将与我们在任何工作中已经利用的开源库的地位相同。

这篇文章中使用的代码可以在我的GitHub上找到 。 它包含CassandraSendMessageFlow的代码,该代码建立与外部Cassandra数据库的连接以保存跟踪样式数据。 它还包含另一个模块,该模块发送HTTP请求作为其基本流扩展的一部分。 如果您在阅读本文后仍然感到好奇,则此存储库可能会有所帮助。

如果您喜欢这篇文章或发现它对您有帮助(或两者都有),请随时在Twitter上@LankyDanDev关注我,并记住与可能对您有用的任何人分享!

翻译自: https://www.javacodegeeks.com/2019/03/extending-overriding-flows-cordapps.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/343430.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【渝粤教育】国家开放大学2018年秋季 0233-21T学前儿童语言教育 参考试题

科目编号&#xff1a;0248 座位号 2018-2019学年度第一学期期末考试 电工电子技术 试题 2019年 1月 一、填空题&#xff08;每小题 6 分 &#xff0c;共计30 分&#xff09; 1.电压是衡量电场力______________ 的物理量&#xff0c;它在数量上等于单位正电荷受电场力作用从电…

工业级光纤收发器的单多模光纤?单多光模块及其用法?

光纤收发器按在光纤中的传输模式可分为&#xff1a;单模光纤和多模光纤&#xff0c;单模光纤收发器和多模光纤收发器最根本的区别就是传输距离远近。今天&#xff0c;就由飞畅科技的小编来为大家介绍下工业级光纤收发器的单/多模光纤的区别&#xff1f;单/多光模块的区别及其应…

【渝粤教育】国家开放大学2018年秋季 0299-21T中国古代文学(1) 参考试题

科目编号&#xff1a;[0314] 座位号 2018-2019学年度第一学期期末考试 兽医基础 试题 2018年 11 月 一、名词解释&#xff08;本大题共5小题&#xff0c;每小题4分&#xff0c;共计20分&#xff09; 1&#xff0e;萎缩 2&#xff0e;动脉性充血 3&#xff0e;黄疸 4&#x…

java ee13_一口气了解多线程及其Java实现

进程&#xff1a;进程就是应用程序在内存中分配的空间&#xff0c;也就是正在运行的程序&#xff0c;各个进程之间不干扰。同时进程保存着程序每一个时刻运行的状态。程序&#xff1a;用某种编程语言(java、python等)编写&#xff0c;能够完成一定任务或者功能的代码集合&#…

apache camel_Apache Camel中的断路器模式

apache camel骆驼通常在分布式环境中用于访问远程资源。 远程服务可能由于各种原因和期间而失败。 对于短时间后暂时不可用且可恢复的服务&#xff0c;重试策略可能会有所帮助。 但是某些服务可能会失败或挂起更长时间&#xff0c;从而使调用应用程序无响应且速度缓慢。 防止级…

【渝粤教育】国家开放大学2018年秋季 0505-22T护理学基础 参考试题

科目编号&#xff1a;0529 座位号&#xff1a; 四川电大2018─2019学年度第一学期期末考试 高级英语阅读&#xff08;1&#xff09;试题 &#xff08;开卷&#xff09; 2019年1月 注 意 事 项 一、 将你的准考证号、学生证号、姓名及分校&#xff08;工作站&#xff09;名称填写…

工业级交换机大致可以分为哪几类?

交换机的用途是非常广泛的&#xff0c;可以这样说&#xff0c;只要是需要联网的地方&#xff0c;基本上都会和交换机相关。我们一般把交换机的使用大致为商用和工业级&#xff0c;商用基本上在公司、单位的办公使用比较常见&#xff0c;今天飞畅科技着重为大家介绍一下工业级交…

【渝粤教育】国家开放大学2018年秋季 0630-22T环境法学 参考试题

科目编号&#xff1a;0633 座位号&#xff1a; 2018-2019学年度第一学期期末考试 化工CAD试题 2019年1月 一、试题一&#xff08;本题50分&#xff09; 设置绘图环境并绘制如下图框标题栏并保存。 二、试题二&#xff08;本题50分&#xff09; 调用图框绘一个平面图形标注…

使用MicroProfile应用隔板和背压

我录制了一段视频&#xff0c;介绍如何使用MicroProfile Fault Tolerance实现隔板和背压。 隔板后面的想法是将应用程序分成几个隔离功能的执行单元。 在企业Java应用程序中&#xff0c;这通常意味着定义多个线程池。 向客户端施加反压将导致向客户端添加有关系统当前压力的信…

【渝粤教育】国家开放大学2018年秋季 0695-21T (1)农业企业经营管理 参考试题

科目编号&#xff1a;[0700] 2018-2019学年度第一学期期末考试 中级会计实务&#xff08;一&#xff09; 评分标准 2019年 1 月 以下给出的是参考答案&#xff0c;请酌情给分。 一、单选题&#xff08;本大题共10小题&#xff0c;每小题3分&#xff0c;共计30分&#xff09; 1…

matlab 形态学 颗粒_数字图像处理Matlab-形态学图像处理(附代码)

这是一篇基于matlab&#xff0c;数字图像处理的形态学研究与实现的文章&#xff0c;希望能对你产生帮助。我还写了一套《数字图像处理》(冈萨雷斯版本)的学习笔记&#xff0c;欢迎关注我的csdn同名主页&#xff0c;一起学习成长~1.Objectives:1&#xff0e;利用 MATLAB 研究二值…

【渝粤教育】国家开放大学2018年秋季 0717-21T社会保障基础 参考试题

科目编号&#xff1a;[0721] 座位号 2018-2019学年度第一学期期末考试 财务管理实务 试题 2019年 1 月 一、单项选则题&#xff08;本大题共10小题&#xff0c;每小题3分&#xff0c;共计30分&#xff09; &#xff08;★请考生务必将答案填入到下面对应序号的答题框中★&…

视频光端机维护三大步骤

视频光端机分为发射端设备和接收端设备&#xff0c;发射端设备和摄像机一样置于室外&#xff0c;工程人员通常是对发射端设备过行维护测试。对于视频光端机的检修工作&#xff0c;我们一般分为三个步骤来进行测试。接下来就由飞畅科技的小编来带大家详细了解下视频光端机维护的…

2021年广东-国家开放大学考试指南(必看)-远程辅助以及微信公众号查题

考前准备工作 一、电脑以及摄像头、浏览器准备 1&#xff1a;一台比较流畅的电脑&#xff0c;这个千万不能马虎&#xff0c;万一考试电脑蓝屏或者卡顿&#xff0c;那是很要命的。 2&#xff1a;摄像头&#xff1a;笔记本有自带的可以用自带的&#xff0c;如果是台式机&#…

java jsonarray 追加_我们如何在Java中将JSONArray添加到JSONObject?

该JSON是用于交换数据的基于文本的格式。它是轻量级的组件&#xff0c;与语言无关。我们还可以将JSONArray添加到JSONObject。我们需要首先将一些项目添加到ArrayList中&#xff0c;并将此列表传递给JSONArray类的put()方法&#xff0c;最后使用put()方法将此数组添加到JSONObj…

内存映射文件 写入 卡住_在Java中使用内存映射文件时检测(写入)失败

内存映射文件 写入 卡住内存映射文件是一个很好的并且经常被忽视的工具。 我不会在这里详细介绍它们的工作方式&#xff08;使用 力 Google Luke&#xff01;&#xff09;&#xff0c;但我将快速总结其优势&#xff1a; 操作系统提供的延迟加载和写入缓存&#xff08;您不必…

飞畅科技——视频光端机用光模块的选型详解

光模块的出现简化了数字视频光端机的设计&#xff0c;我们只要把光模块当作一个具有光电转换功能的部件就可以了。那么针对各种不同的光端机&#xff0c;应该怎样选择相应的光模块呢&#xff1f;接下来就由飞畅科技的小编来为大家详细介绍下视频光端机用光模块的选型&#xff0…

视频监控中的光端机是干什么用的?

现如今&#xff0c;随着社会的进步和经济的发展&#xff0c;人民生活开始富裕&#xff0c;经济宽裕的家庭用户已开始考虑使用监控产品来保护自己&#xff0c;监控已经呈现融入家庭生活的趋势。就数字监控而言&#xff0c;虽然是后起之秀&#xff0c;但依然是现阶段发展趋势。光…

每个Java开发人员都应该知道的10个基本工具

大家好&#xff0c;我们已经到了2019年的第二个月&#xff0c;我相信你们所有人都已经为2019年的学习目标以及如何实现这些目标制定了目标。 我一直在撰写一系列文章&#xff0c;为您提供一些知识&#xff0c;使您可以学习和改进以成为2019年更好的全方位开发人员&#xff0c;例…

java怎么使异常不起作用_java – @Test(expected = Exception.class)对我不起作用,我错过了什么?...

我正在使用sts,但也在命令行上使用mvn clean install.我创建了这个简单的测试作为例子.import org.junit.Test;import junit.framework.TestCase;public class QuickTest extends TestCase {Test(expected Exception.class)public void test() {throwsException();}private vo…