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 testChainFuture() throws Throwable {
        CompletableFuture<Integer> sourceFuture = new CompletableFuture<>();
        CompletableFuture<Number> destinationFuture = new CompletableFuture<>();
        FutureUtils.chainFuture(sourceFuture, destinationFuture);
        assertFalse(sourceFuture.isDone());
        assertFalse(destinationFuture.isDone());
        assertFalse(sourceFuture.isCancelled());
        assertFalse(destinationFuture.isCancelled());
        assertFalse(sourceFuture.isCompletedExceptionally());
        assertFalse(destinationFuture.isCompletedExceptionally());
        sourceFuture.complete(123);
        assertEquals(123, destinationFuture.get());
    }