Skip to content

Commit ee89344

Browse files
committed
Fixed exception unwrapping in fast-path of CompletableFuture.await()
1 parent 6e8a92c commit ee89344

File tree

2 files changed

+30
-3
lines changed
  • kotlinx-coroutines-jdk8/src
    • main/kotlin/kotlinx/coroutines/experimental/future
    • test/kotlin/kotlinx/coroutines/experimental/future

2 files changed

+30
-3
lines changed

kotlinx-coroutines-jdk8/src/main/kotlin/kotlinx/coroutines/experimental/future/Future.kt

+14-3
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,19 @@ public fun <T> Deferred<T>.toCompletableFuture(): CompletableFuture<T> {
5050
* If the [Job] of the current coroutine is completed while this suspending function is waiting, this function
5151
* immediately resumes with [CancellationException] .
5252
*/
53-
public suspend fun <T> CompletableFuture<T>.await(): T =
54-
// quick check if already complete (avoid extra object creation)
55-
if (isDone) get() else suspendCancellableCoroutine { cont: CancellableContinuation<T> ->
53+
public suspend fun <T> CompletableFuture<T>.await(): T {
54+
if (isDone) {
55+
// then only way to get unwrapped exception from the CompletableFuture...
56+
var result: T? = null
57+
var exception: Throwable? = null
58+
whenComplete { r, e ->
59+
result = r
60+
exception = e
61+
}
62+
if (exception != null) throw exception!!
63+
return result as T
64+
}
65+
return suspendCancellableCoroutine { cont: CancellableContinuation<T> ->
5666
val completionFuture = whenComplete { result, exception ->
5767
if (exception == null) // the future has been completed normally
5868
cont.resume(result)
@@ -62,6 +72,7 @@ public suspend fun <T> CompletableFuture<T>.await(): T =
6272
cont.cancelFutureOnCompletion(completionFuture)
6373
Unit
6474
}
75+
}
6576

6677
private class CompletableFutureCoroutine<T>(
6778
override val context: CoroutineContext

kotlinx-coroutines-jdk8/src/test/kotlin/kotlinx/coroutines/experimental/future/FutureTest.kt

+16
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,22 @@ class FutureTest {
3737
assertEquals("OK", future.get())
3838
}
3939

40+
@Test
41+
fun testDoneFutureCompletedExceptionally() {
42+
val toAwait = CompletableFuture<String>()
43+
toAwait.completeExceptionally(RuntimeException("O"))
44+
val future = future<String> {
45+
try {
46+
toAwait.await()
47+
} catch (e: RuntimeException) {
48+
e.message!!
49+
} + "K"
50+
}
51+
52+
assertFalse(future.isDone)
53+
assertEquals("OK", future.get())
54+
}
55+
4056
@Test
4157
fun testAwaitedFutureCompletedExceptionally() {
4258
val toAwait = CompletableFuture<String>()

0 commit comments

Comments
 (0)