Skip to content

Commit

Permalink
Fixed exception unwrapping in fast-path of CompletableFuture.await()
Browse files Browse the repository at this point in the history
  • Loading branch information
elizarov committed Jan 19, 2017
1 parent 6e8a92c commit ee89344
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,19 @@ public fun <T> Deferred<T>.toCompletableFuture(): CompletableFuture<T> {
* If the [Job] of the current coroutine is completed while this suspending function is waiting, this function
* immediately resumes with [CancellationException] .
*/
public suspend fun <T> CompletableFuture<T>.await(): T =
// quick check if already complete (avoid extra object creation)
if (isDone) get() else suspendCancellableCoroutine { cont: CancellableContinuation<T> ->
public suspend fun <T> CompletableFuture<T>.await(): T {
if (isDone) {
// then only way to get unwrapped exception from the CompletableFuture...
var result: T? = null
var exception: Throwable? = null
whenComplete { r, e ->
result = r
exception = e
}
if (exception != null) throw exception!!
return result as T
}
return suspendCancellableCoroutine { cont: CancellableContinuation<T> ->
val completionFuture = whenComplete { result, exception ->
if (exception == null) // the future has been completed normally
cont.resume(result)
Expand All @@ -62,6 +72,7 @@ public suspend fun <T> CompletableFuture<T>.await(): T =
cont.cancelFutureOnCompletion(completionFuture)
Unit
}
}

private class CompletableFutureCoroutine<T>(
override val context: CoroutineContext
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,22 @@ class FutureTest {
assertEquals("OK", future.get())
}

@Test
fun testDoneFutureCompletedExceptionally() {
val toAwait = CompletableFuture<String>()
toAwait.completeExceptionally(RuntimeException("O"))
val future = future<String> {
try {
toAwait.await()
} catch (e: RuntimeException) {
e.message!!
} + "K"
}

assertFalse(future.isDone)
assertEquals("OK", future.get())
}

@Test
fun testAwaitedFutureCompletedExceptionally() {
val toAwait = CompletableFuture<String>()
Expand Down

0 comments on commit ee89344

Please sign in to comment.