From 886a97de77af93cd5c71b01dd025dc2992cd59ee Mon Sep 17 00:00:00 2001 From: Jerry Lee Date: Sun, 2 Jun 2024 17:24:38 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20report=20exception=20info=20of=20peek?= =?UTF-8?q?=20action,=20errors=20should=20never=20pass=20silently=20?= =?UTF-8?q?=F0=9F=92=A3=20=F0=9F=91=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/io/foldright/cffu/Cffu.java | 12 ++++---- .../cffu/CompletableFutureUtils.java | 30 ++++++++++++++----- .../kotlin/CompletableFutureExtensions.kt | 13 ++++---- 3 files changed, 35 insertions(+), 20 deletions(-) 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 a7894cf7..3f8637c6 100644 --- a/cffu-core/src/main/java/io/foldright/cffu/Cffu.java +++ b/cffu-core/src/main/java/io/foldright/cffu/Cffu.java @@ -1319,8 +1319,8 @@ public Cffu whenCompleteAsync(BiConsumer action * Peeks the result by executing the given action when this cffu completes, returns this cffu. *

* When this cffu is complete, the given action is invoked with the result (or {@code null} if none) - * and the exception (or {@code null} if none) of this cffu as arguments. - * Whether the supplied action throws an exception or not, do NOT affect this cffu. + * and the exception (or {@code null} if none) of this cffu as arguments. Whether the supplied action + * throws an exception or not, this cffu is NOT affected. *

* Unlike method {@link CompletionStage#handle handle} and like method * {@link CompletionStage#whenComplete(BiConsumer) whenComplete}, @@ -1341,8 +1341,8 @@ public Cffu peek(BiConsumer action) { * executes the given action using {@link #defaultExecutor()}, returns this cffu. *

* When this cffu is complete, the given action is invoked with the result (or {@code null} if none) - * and the exception (or {@code null} if none) of this cffu as arguments. - * Whether the supplied action throws an exception or not, do NOT affect this cffu. + * and the exception (or {@code null} if none) of this cffu as arguments. Whether the supplied action + * throws an exception or not, this cffu is NOT affected. *

* Unlike method {@link CompletionStage#handle handle} and like method * {@link CompletionStage#whenComplete(BiConsumer) whenComplete}, @@ -1362,8 +1362,8 @@ public Cffu peekAsync(BiConsumer action) { * that executes the given action using the supplied Executor when this cffu completes, returns this cffu. *

* When this cffu is complete, the given action is invoked with the result (or {@code null} if none) - * and the exception (or {@code null} if none) of this cffu as arguments. - * Whether the supplied action throws an exception or not, do NOT affect this cffu. + * and the exception (or {@code null} if none) of this cffu as arguments. Whether the supplied action + * throws an exception or not, this cffu is NOT affected. *

* Unlike method {@link CompletionStage#handle handle} and like method * {@link CompletionStage#whenComplete(BiConsumer) whenComplete}, 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 6d1db59b..6e57d8fb 100644 --- a/cffu-core/src/main/java/io/foldright/cffu/CompletableFutureUtils.java +++ b/cffu-core/src/main/java/io/foldright/cffu/CompletableFutureUtils.java @@ -10,6 +10,8 @@ import org.jetbrains.annotations.Contract; import javax.annotation.ParametersAreNonnullByDefault; +import java.io.PrintWriter; +import java.io.StringWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -1252,8 +1254,8 @@ public static CompletableFuture applyToEitherSuccessAsync( * Peeks the result by executing the given action when given stage completes, returns the given stage. *

* When the given stage is complete, the given action is invoked with the result (or {@code null} if none) - * and the exception (or {@code null} if none) of given stage as arguments. - * Whether the supplied action throws an exception or not, do NOT affect this cffu. + * and the exception (or {@code null} if none) of given stage as arguments. Whether the supplied action + * throws an exception or not, the given stage is NOT affected. *

* Unlike method {@link CompletionStage#handle handle} and like method * {@link CompletionStage#whenComplete(BiConsumer) whenComplete}, @@ -1269,7 +1271,7 @@ C peek(C cf, BiConsumer action) { requireNonNull(cf, "cf is null"); requireNonNull(action, "action is null"); - cf.whenComplete(action); + cf.whenComplete(action).exceptionally(CompletableFutureUtils::reportExceptionInfoOfPeekAction); return cf; } @@ -1279,8 +1281,8 @@ C peek(C cf, BiConsumer action) { * returns the given stage. *

* When the given stage is complete, the given action is invoked with the result (or {@code null} if none) - * and the exception (or {@code null} if none) of given stage as arguments. - * Whether the supplied action throws an exception or not, do NOT affect this cffu. + * and the exception (or {@code null} if none) of given stage as arguments. Whether the supplied action + * throws an exception or not, the given stage is NOT affected. *

* Unlike method {@link CompletionStage#handle handle} and like method * {@link CompletionStage#whenComplete(BiConsumer) whenComplete}, @@ -1301,8 +1303,8 @@ C peekAsync(C cf, BiConsumer action) { * executes the given action using the supplied Executor, returns the given stage. *

* When the given stage is complete, the given action is invoked with the result (or {@code null} if none) - * and the exception (or {@code null} if none) of given stage as arguments. - * Whether the supplied action throws an exception or not, do NOT affect this cffu. + * and the exception (or {@code null} if none) of given stage as arguments. Whether the supplied action + * throws an exception or not, the given stage is NOT affected. *

* Unlike method {@link CompletionStage#handle handle} and like method * {@link CompletionStage#whenComplete(BiConsumer) whenComplete}, @@ -1319,10 +1321,22 @@ C peekAsync(C cf, BiConsumer action, Executor exec requireNonNull(action, "action is null"); requireNonNull(executor, "executor is null"); - cf.whenCompleteAsync(action, executor); + cf.whenCompleteAsync(action, executor).exceptionally(CompletableFutureUtils::reportExceptionInfoOfPeekAction); return cf; } + @Nullable + private static T reportExceptionInfoOfPeekAction(Throwable ex) { + StringWriter sw = new StringWriter(4096); + PrintWriter writer = new PrintWriter(sw); + + writer.println("Unexpected exception occurred in the action of peek:"); + ex.printStackTrace(writer); + + System.err.println(sw); + return null; + } + //////////////////////////////////////////////////////////////////////////////// //# Backport CF static methods + related enhanced methods // compatibility for low Java versions 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 60018f8f..8a6f1fd1 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 @@ -5,6 +5,7 @@ package io.foldright.cffu.kotlin import io.foldright.cffu.Cffu import io.foldright.cffu.CffuState import io.foldright.cffu.CompletableFutureUtils +import java.util.* import java.util.concurrent.* import java.util.function.* import java.util.function.Function @@ -655,8 +656,8 @@ fun CompletionStage.applyToEitherSuccessAsync( * Peeks the result by executing the given action when this stage completes, returns this stage. * * When this stage is complete, the given action is invoked with the result (or `null` if none) - * and the exception (or `null` if none) of this stage as arguments. - * Whether the supplied action throws an exception or not, do **NOT** affect this cffu. + * and the exception (or `null` if none) of given stage as arguments. Whether the supplied action + * throws an exception or not, this stage is **NOT** affected. * * Unlike method [handle][CompletionStage.handle] and like method [whenComplete][CompletionStage.whenComplete], * this method is not designed to translate completion outcomes. @@ -674,8 +675,8 @@ fun > C.peek(action: BiConsumer> C.peekAsync(action: BiConsumer