From fec2ef2fd38d04ac8b9c599422e3e937d8f64f20 Mon Sep 17 00:00:00 2001 From: Chris Rankin Date: Tue, 3 Mar 2020 15:01:12 +0000 Subject: [PATCH] CORDA-3638: Allow CordaFuture to complete even if an Error is thrown. (#5994) * Allow CordaFuture to complete even if an Error is thrown. * Allow CordaFuture.flatMap() to notify for failures due to Error. --- .../core/internal/concurrent/CordaFutureImpl.kt | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/core/src/main/kotlin/net/corda/core/internal/concurrent/CordaFutureImpl.kt b/core/src/main/kotlin/net/corda/core/internal/concurrent/CordaFutureImpl.kt index 02cf0706c8..dcaceb2295 100644 --- a/core/src/main/kotlin/net/corda/core/internal/concurrent/CordaFutureImpl.kt +++ b/core/src/main/kotlin/net/corda/core/internal/concurrent/CordaFutureImpl.kt @@ -78,6 +78,7 @@ fun CordaFuture.mapError(transform: (Throwable) -> Throwa * But if this future or the transform fails, the returned future's outcome is the same throwable. * In the case where this future fails, the transform is not invoked. */ +@Suppress("TooGenericExceptionCaught") fun CordaFuture.flatMap(transform: (V) -> CordaFuture): CordaFuture = CordaFutureImpl().also { result -> thenMatch(success@ { result.captureLater(try { @@ -85,6 +86,9 @@ fun CordaFuture.flatMap(transform: (V) -> CordaFuture): Cor } catch (e: Exception) { result.setException(e) return@success + } catch (t: Throwable) { + result.setException(t) + throw t }) }, { result.setException(it) @@ -136,11 +140,15 @@ interface ValueOrException { fun captureLater(f: CordaFuture) = f.then { capture { f.getOrThrow() } } /** Run the given block (in the foreground) and set this future to its outcome. */ + @Suppress("TooGenericExceptionCaught") fun capture(block: () -> V): Boolean { return set(try { block() } catch (e: Exception) { return setException(e) + } catch (t: Throwable) { + setException(t) + throw t }) } } @@ -160,12 +168,16 @@ internal class CordaFutureImpl(private val impl: CompletableFuture = Compl override fun setException(t: Throwable) = impl.completeExceptionally(t) override fun then(callback: (CordaFuture) -> W) = thenImpl(defaultLog, callback) /** For testing only. */ + @Suppress("TooGenericExceptionCaught") internal fun thenImpl(log: Logger, callback: (CordaFuture) -> W) { impl.whenComplete { _, _ -> try { callback(this) } catch (e: Exception) { log.error(listenerFailedMessage, e) + } catch (t: Throwable) { + log.error(listenerFailedMessage, t) + throw t } } }