public static <T> void chainFuture(
        CompletableFuture<? extends T> sourceFuture,
        CompletableFuture<T> destinationFuture
    ) {
        sourceFuture.whenComplete((BiConsumer<T, Throwable>) (val, throwable) -> {
            if (throwable != null) {
                destinationFuture.completeExceptionally(throwable);
            } else {
                destinationFuture.complete(val);
            }
        });
    }
@Test
    public void testChainFutureExceptionally() {
        CompletableFuture<Integer> sourceFuture = new CompletableFuture<>();
        CompletableFuture<Number> destinationFuture = new CompletableFuture<>();
        FutureUtils.chainFuture(sourceFuture, destinationFuture);
        sourceFuture.completeExceptionally(new RuntimeException("source failed"));
        Throwable cause = assertThrows(ExecutionException.class,
                () -> destinationFuture.get()).getCause();
        assertEquals(RuntimeException.class, cause.getClass());
        assertEquals("source failed", cause.getMessage());
    }