diff --git a/cffu-core/src/main/java/io/foldright/cffu/Cffu.java b/cffu-core/src/main/java/io/foldright/cffu/Cffu.java index ef94e3d0..3f8637c6 100644 --- a/cffu-core/src/main/java/io/foldright/cffu/Cffu.java +++ b/cffu-core/src/main/java/io/foldright/cffu/Cffu.java @@ -946,11 +946,6 @@ public Cffu exceptionallyAsync(Function fn, Executor * if not otherwise completed before the given timeout. *

* Uses {@link #defaultExecutor()} as {@code executorWhenTimeout}. - *

- * CAUTION:
- * If the wait timed out, the returned Cffu complete exceptionally with a CompletionException holding - * the {@link TimeoutException} as its cause; NOT a direct {@link TimeoutException} - * like {@link #unsafeOrTimeout(long, TimeUnit)}/{@link CompletableFuture#orTimeout(long, TimeUnit)}. * * @param timeout how long to wait before completing exceptionally with a TimeoutException, in units of {@code unit} * @param unit a {@code TimeUnit} determining how to interpret the {@code timeout} parameter @@ -964,11 +959,6 @@ public Cffu orTimeout(long timeout, TimeUnit unit) { /** * Exceptionally completes this Cffu with a {@link TimeoutException} * if not otherwise completed before the given timeout. - *

- * CAUTION:
- * If the wait timed out, the returned Cffu complete exceptionally with a CompletionException holding - * the {@link TimeoutException} as its cause; NOT a direct {@link TimeoutException} - * like {@link #unsafeOrTimeout(long, TimeUnit)}/{@link CompletableFuture#orTimeout(long, TimeUnit)}. * * @param executorWhenTimeout the async executor when triggered by timeout * @param timeout how long to wait before completing exceptionally with a TimeoutException, in units of {@code unit} diff --git a/cffu-core/src/main/java/io/foldright/cffu/CompletableFutureUtils.java b/cffu-core/src/main/java/io/foldright/cffu/CompletableFutureUtils.java index e98ed329..ae22c2e6 100644 --- a/cffu-core/src/main/java/io/foldright/cffu/CompletableFutureUtils.java +++ b/cffu-core/src/main/java/io/foldright/cffu/CompletableFutureUtils.java @@ -1487,11 +1487,6 @@ C exceptionallyAsync(C cf, Function fn, Executor executo * if not otherwise completed before the given timeout. *

* Uses CompletableFuture's default asynchronous execution facility as {@code executorWhenTimeout}. - *

- * CAUTION:
- * If the wait timed out, the returned CompletableFuture complete exceptionally with a CompletionException holding - * the {@link TimeoutException} as its cause; NOT a direct {@link TimeoutException} - * like {@link #orTimeout(CompletableFuture, long, TimeUnit)}/{@link CompletableFuture#orTimeout(long, TimeUnit)}. * * @param timeout how long to wait before completing exceptionally with a TimeoutException, in units of {@code unit} * @param unit a {@code TimeUnit} determining how to interpret the {@code timeout} parameter @@ -1505,11 +1500,6 @@ public static > C cffuOrTimeout(C cf, long timeou /** * Exceptionally completes given CompletableFuture with a {@link TimeoutException} * if not otherwise completed before the given timeout. - *

- * CAUTION:
- * If the wait timed out, the returned CompletableFuture complete exceptionally with a CompletionException holding - * the {@link TimeoutException} as its cause; NOT a direct {@link TimeoutException} - * like {@link #orTimeout(CompletableFuture, long, TimeUnit)}/{@link CompletableFuture#orTimeout(long, TimeUnit)}. * * @param executorWhenTimeout the async executor when triggered by timeout * @param timeout how long to wait before completing exceptionally with a TimeoutException, in units of {@code unit} @@ -1646,17 +1636,20 @@ C completeOnTimeout(C cf, @Nullable T value, long timeout, TimeUnit unit) { @SuppressWarnings("unchecked") private static > C hopExecutorIfAtCfDelayerThread(C cf, Executor asyncExecutor) { - final CompletionStage f = (CompletionStage) cf; + CompletableFuture ret = newIncompleteFuture(cf); - return (C) f.handle((v, ex) -> null).thenCompose(unused -> { - if (!atCfDelayerThread()) return f; + cf.whenComplete((v, ex) -> { + if (!atCfDelayerThread()) completeCf(ret, v, ex); + else delayedExecutor(0, TimeUnit.SECONDS, asyncExecutor) + .execute(() -> completeCf(ret, v, ex)); + }); - CompletableFuture signal = new CompletableFuture<>(); - delayedExecutor(0, TimeUnit.SECONDS, asyncExecutor) - .execute(() -> signal.complete(null)); + return (C) ret; + } - return signal.thenCompose(v -> f); - }); + private static void completeCf(CompletableFuture cf, Object value, @Nullable Throwable ex) { + if (ex == null) cf.complete(value); + else cf.completeExceptionally(ex); } //# Advanced methods of CompletionStage diff --git a/cffu-core/src/test/java/io/foldright/cffu/CompletableFutureUtilsTest.java b/cffu-core/src/test/java/io/foldright/cffu/CompletableFutureUtilsTest.java index f5261b34..5b0d850d 100644 --- a/cffu-core/src/test/java/io/foldright/cffu/CompletableFutureUtilsTest.java +++ b/cffu-core/src/test/java/io/foldright/cffu/CompletableFutureUtilsTest.java @@ -1043,17 +1043,13 @@ void test_safeBehavior_orTimeout() { }).join()); assertEquals(n, cffuOrTimeout(createIncompleteFuture(), 5, TimeUnit.MILLISECONDS).handle((r, ex) -> { - // FIXME: Not TimeoutException, not compatible with orTimeout method - assertInstanceOf(CompletionException.class, ex); - assertInstanceOf(TimeoutException.class, ex.getCause()); + assertInstanceOf(TimeoutException.class, ex); assertFalse(Delayer.atCfDelayerThread()); assertNotSame(testThread, currentThread()); return n; }).join()); assertEquals(n, cffuOrTimeout(createIncompleteFuture(), executorService, 5, TimeUnit.MILLISECONDS).handle((r, ex) -> { - // FIXME: Not TimeoutException, not compatible with orTimeout method - assertInstanceOf(CompletionException.class, ex); - assertInstanceOf(TimeoutException.class, ex.getCause()); + assertInstanceOf(TimeoutException.class, ex); assertFalse(Delayer.atCfDelayerThread()); assertTrue(TestThreadPoolManager.isRunInExecutor(executorService)); return n; diff --git a/cffu-kotlin/src/main/java/io/foldright/cffu/kotlin/CompletableFutureExtensions.kt b/cffu-kotlin/src/main/java/io/foldright/cffu/kotlin/CompletableFutureExtensions.kt index cafaad70..8db439e1 100644 --- a/cffu-kotlin/src/main/java/io/foldright/cffu/kotlin/CompletableFutureExtensions.kt +++ b/cffu-kotlin/src/main/java/io/foldright/cffu/kotlin/CompletableFutureExtensions.kt @@ -771,9 +771,6 @@ fun > C.exceptionallyAsync(fn: Function> C.cffuOrTimeout(timeout: Long, unit: TimeU * Exceptionally completes this CompletableFuture with a TimeoutException * if not otherwise completed before the given timeout. * - * **CAUTION:** If the wait timed out, the returned CompletableFuture complete exceptionally with a CompletionException - * holding the [TimeoutException] as its cause; NOT a direct [TimeoutException] like [orTimeout]/[CompletableFuture.orTimeout]. - * * @param executorWhenTimeout the async executor when triggered by timeout * @param timeout how long to wait before completing exceptionally with a TimeoutException, in units of `unit` * @param unit a `TimeUnit` determining how to interpret the `timeout` parameter