diff --git a/core-tests/src/test/kotlin/net/corda/coretests/flows/FlowExternalAsyncOperationTest.kt b/core-tests/src/test/kotlin/net/corda/coretests/flows/FlowExternalAsyncOperationTest.kt index cec2568214..cbf1892e51 100644 --- a/core-tests/src/test/kotlin/net/corda/coretests/flows/FlowExternalAsyncOperationTest.kt +++ b/core-tests/src/test/kotlin/net/corda/coretests/flows/FlowExternalAsyncOperationTest.kt @@ -177,12 +177,14 @@ class FlowExternalAsyncOperationTest : AbstractFlowExternalOperationTest() { FlowWithExternalProcess(party) { @Suspendable - override fun testCode(): Any = - await(ExternalAsyncOperation(serviceHub) { _, _ -> + override fun testCode(): Any { + val e = createException() + return await(ExternalAsyncOperation(serviceHub) { _, _ -> CompletableFuture().apply { - completeExceptionally(createException()) + completeExceptionally(e) } }) + } private fun createException() = when (exceptionType) { HospitalizeFlowException::class.java -> HospitalizeFlowException("keep it around") diff --git a/core-tests/src/test/kotlin/net/corda/coretests/flows/FlowExternalOperationTest.kt b/core-tests/src/test/kotlin/net/corda/coretests/flows/FlowExternalOperationTest.kt index 1b78e95732..5fe3809684 100644 --- a/core-tests/src/test/kotlin/net/corda/coretests/flows/FlowExternalOperationTest.kt +++ b/core-tests/src/test/kotlin/net/corda/coretests/flows/FlowExternalOperationTest.kt @@ -235,7 +235,10 @@ class FlowExternalOperationTest : AbstractFlowExternalOperationTest() { FlowWithExternalProcess(party) { @Suspendable - override fun testCode(): Any = await(ExternalOperation(serviceHub) { _, _ -> throw createException() }) + override fun testCode() { + val e = createException() + await(ExternalOperation(serviceHub) { _, _ -> throw e }) + } private fun createException() = when (exceptionType) { HospitalizeFlowException::class.java -> HospitalizeFlowException("keep it around") diff --git a/core/src/main/kotlin/net/corda/core/flows/FlowLogic.kt b/core/src/main/kotlin/net/corda/core/flows/FlowLogic.kt index 79c7e1c36d..8e4abdb05a 100644 --- a/core/src/main/kotlin/net/corda/core/flows/FlowLogic.kt +++ b/core/src/main/kotlin/net/corda/core/flows/FlowLogic.kt @@ -565,12 +565,7 @@ abstract class FlowLogic { @Suspendable fun await(operation: FlowExternalAsyncOperation): R { // Wraps the passed in [FlowExternalAsyncOperation] so its [CompletableFuture] can be converted into a [CordaFuture] - val flowAsyncOperation = object : FlowAsyncOperation, WrappedFlowExternalAsyncOperation { - override val operation = operation - override fun execute(deduplicationId: String): CordaFuture { - return this.operation.execute(deduplicationId).asCordaFuture() - } - } + val flowAsyncOperation = WrappedFlowExternalAsyncOperation(operation) val request = FlowIORequest.ExecuteAsyncOperation(flowAsyncOperation) return stateMachine.suspend(request, false) } @@ -584,18 +579,7 @@ abstract class FlowLogic { */ @Suspendable fun await(operation: FlowExternalOperation): R { - val flowAsyncOperation = object : FlowAsyncOperation, WrappedFlowExternalOperation { - override val serviceHub = this@FlowLogic.serviceHub as ServiceHubCoreInternal - override val operation = operation - override fun execute(deduplicationId: String): CordaFuture { - // Using a [CompletableFuture] allows unhandled exceptions to be thrown inside the background operation - // the exceptions will be set on the future by [CompletableFuture.AsyncSupply.run] - return CompletableFuture.supplyAsync( - Supplier { this.operation.execute(deduplicationId) }, - serviceHub.externalOperationExecutor - ).asCordaFuture() - } - } + val flowAsyncOperation = WrappedFlowExternalOperation(serviceHub as ServiceHubCoreInternal, operation) val request = FlowIORequest.ExecuteAsyncOperation(flowAsyncOperation) return stateMachine.suspend(request, false) } @@ -605,21 +589,32 @@ abstract class FlowLogic { * [WrappedFlowExternalAsyncOperation] is added to allow jackson to properly reference the data stored within the wrapped * [FlowExternalAsyncOperation]. */ -private interface WrappedFlowExternalAsyncOperation { - val operation: FlowExternalAsyncOperation +private class WrappedFlowExternalAsyncOperation(val operation: FlowExternalAsyncOperation) : FlowAsyncOperation { + override fun execute(deduplicationId: String): CordaFuture { + return operation.execute(deduplicationId).asCordaFuture() + } } /** * [WrappedFlowExternalOperation] is added to allow jackson to properly reference the data stored within the wrapped * [FlowExternalOperation]. * - * The reference to [ServiceHub] is is also needed by Kryo to properly keep a reference to [ServiceHub] so that + * The reference to [ServiceHub] is also needed by Kryo to properly keep a reference to [ServiceHub] so that * [FlowExternalOperation] can be run from the [ServiceHubCoreInternal.externalOperationExecutor] without causing errors when retrying a * flow. A [NullPointerException] is thrown if [FlowLogic.serviceHub] is accessed from [FlowLogic.await] when retrying a flow. */ -private interface WrappedFlowExternalOperation { - val serviceHub: ServiceHub +private class WrappedFlowExternalOperation( + val serviceHub: ServiceHubCoreInternal, val operation: FlowExternalOperation +) : FlowAsyncOperation { + override fun execute(deduplicationId: String): CordaFuture { + // Using a [CompletableFuture] allows unhandled exceptions to be thrown inside the background operation + // the exceptions will be set on the future by [CompletableFuture.AsyncSupply.run] + return CompletableFuture.supplyAsync( + Supplier { this.operation.execute(deduplicationId) }, + serviceHub.externalOperationExecutor + ).asCordaFuture() + } } /**