io.gravitee.fetcher.http.vertx.VertxCompletableFuture.java Source code

Java tutorial

Introduction

Here is the source code for io.gravitee.fetcher.http.vertx.VertxCompletableFuture.java

Source

/**
 * Copyright (C) 2015 The Gravitee team (http://gravitee.io)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.gravitee.fetcher.http.vertx;

import io.vertx.core.AsyncResult;
import io.vertx.core.Context;
import io.vertx.core.Future;
import io.vertx.core.Vertx;

import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.Executor;
import java.util.function.*;

/**
 * An implementation of {@link CompletableFuture} for Vert.x. It differs in the way to handle async calls:
 * <p>
 * * {@link VertxCompletableFuture} are attached to a Vert.x {@link Context}
 * * All operator methods returns {@link VertxCompletableFuture}
 * * <em*async</em> method not passing an {@link Executor} are executed on the attached {@link Context}
 * * All non async method are executed on the current Thread (so not necessary on the attached {@link Context}
 * <p>
 * The class also offer bridges methods with Vert.x {@link Future}, and regular {@link CompletableFuture}.
 *
 * @param <T> the expected type of result
 */
@SuppressWarnings("WeakerAccess")
public class VertxCompletableFuture<T> extends CompletableFuture<T> implements CompletionStage<T> {
    private final Executor executor;

    /**
     * The {@link Context} used by the future.
     */
    private final Context context;

    // ============= Constructors =============

    /**
     * Creates an instance of {@link VertxCompletableFuture}, using the current Vert.x context or create a new one.
     *
     * @param vertx the Vert.x instance
     */
    public VertxCompletableFuture(Vertx vertx) {
        this(Objects.requireNonNull(vertx).getOrCreateContext());
    }

    /**
     * Creates an instance of {@link VertxCompletableFuture}, using the given {@link Context}.
     *
     * @param context the context
     */
    public VertxCompletableFuture(Context context) {
        this.context = Objects.requireNonNull(context);
        this.executor = command -> context.runOnContext(v -> command.run());
    }

    /**
     * Creates a new {@link VertxCompletableFuture} from the given context and given {@link CompletableFuture}.
     * The created {@link VertxCompletableFuture} is completed successfully or not when the given completable future
     * completes successfully or not.
     *
     * @param context the context
     * @param future  the completable future
     */
    private VertxCompletableFuture(Context context, CompletableFuture<T> future) {
        this(context);
        Objects.requireNonNull(future).whenComplete((res, err) -> {
            if (err != null) {
                completeExceptionally(err);
            } else {
                complete(res);
            }
        });
    }

    /**
     * Creates a new {@link VertxCompletableFuture} using the current {@link Context}. This method
     * <strong>must</strong> be used from a Vert.x thread, or fails.
     */
    public VertxCompletableFuture() {
        this(Vertx.currentContext());
    }

    // ============= Factory methods (from) =============

    /**
     * Creates a new {@link VertxCompletableFuture} from the given {@link Vertx} instance and given
     * {@link CompletableFuture}. The returned future uses the current Vert.x context, or creates a new one.
     * <p>
     * The created {@link VertxCompletableFuture} is completed successfully or not when the given completable future
     * completes successfully or not.
     *
     * @param vertx  the Vert.x instance
     * @param future the future
     * @param <T>    the type of the result
     * @return the new {@link VertxCompletableFuture}
     */
    public static <T> VertxCompletableFuture<T> from(Vertx vertx, CompletableFuture<T> future) {
        return from(vertx.getOrCreateContext(), future);
    }

    /**
     * Creates a new {@link VertxCompletableFuture} from the given {@link Context} instance and given
     * {@link Future}. The returned future uses the current Vert.x context, or creates a new one.
     * <p>
     * The created {@link VertxCompletableFuture} is completed successfully or not when the given future
     * completes successfully or not.
     *
     * @param vertx  the Vert.x instance
     * @param future the Vert.x future
     * @param <T>    the type of the result
     * @return the new {@link VertxCompletableFuture}
     */
    public static <T> VertxCompletableFuture<T> from(Vertx vertx, Future<T> future) {
        return from(vertx.getOrCreateContext(), future);
    }

    /**
     * Creates a {@link VertxCompletableFuture} from the given {@link Context} and {@link CompletableFuture}.
     * <p>
     * The created {@link VertxCompletableFuture} is completed successfully or not when the given future
     * completes successfully or not. The completion is called on the given {@link Context}, immediately if it is
     * already executing on the right context, asynchronously if not.
     *
     * @param context the context
     * @param future  the future
     * @param <T>     the type of result
     * @return the creation {@link VertxCompletableFuture}
     */
    public static <T> VertxCompletableFuture<T> from(Context context, CompletableFuture<T> future) {
        VertxCompletableFuture<T> res = new VertxCompletableFuture<>(Objects.requireNonNull(context));
        Objects.requireNonNull(future).whenComplete((result, error) -> {
            if (context == Vertx.currentContext()) {
                res.complete(result, error);
            } else {
                res.context.runOnContext(v -> res.complete(result, error));
            }
        });
        return res;
    }

    /**
     * Creates a new {@link VertxCompletableFuture} from the given {@link Context} instance and given
     * {@link Future}. The returned future uses the current Vert.x context, or creates a new one.
     * <p>
     * The created {@link VertxCompletableFuture} is completed successfully or not when the given future
     * completes successfully or not. The created {@link VertxCompletableFuture} is completed successfully or not
     * when the given future completes successfully or not. The completion is called on the given {@link Context},
     * immediately if it is already executing on the right context, asynchronously if not.
     *
     * @param context the context
     * @param future  the Vert.x future
     * @param <T>     the type of the result
     * @return the new {@link VertxCompletableFuture}
     */
    public static <T> VertxCompletableFuture<T> from(Context context, Future<T> future) {
        VertxCompletableFuture<T> res = new VertxCompletableFuture<>(Objects.requireNonNull(context));
        Objects.requireNonNull(future).setHandler(ar -> {
            if (context == Vertx.currentContext()) {
                res.completeFromAsyncResult(ar);
            } else {
                res.context.runOnContext(v -> res.completeFromAsyncResult(ar));
            }
        });
        return res;
    }

    /**
     * Returns a new CompletableFuture that is asynchronously completed by a task running in the current Vert.x
     * {@link Context} with the value obtained by calling the given Supplier.
     * <p>
     * This method is different from {@link CompletableFuture#supplyAsync(Supplier)} as it does not use a fork join
     * executor, but use the Vert.x context.
     *
     * @param vertx    the Vert.x instance
     * @param supplier a function returning the value to be used to complete the returned CompletableFuture
     * @param <T>      the function's return type
     * @return the new CompletableFuture
     */
    public static <T> VertxCompletableFuture<T> supplyAsync(Vertx vertx, Supplier<T> supplier) {
        return supplyAsync(Objects.requireNonNull(vertx).getOrCreateContext(), supplier);
    }

    /**
     * Returns a new CompletableFuture that is asynchronously completed by a task running in the
     * current Vert.x {@link Context} after it runs the given action.
     * <p>
     * This method is different from {@link CompletableFuture#supplyAsync(Supplier)} as it does not use a fork join
     * executor, but use the Vert.x context.
     *
     * @param vertx    the Vert.x instance
     * @param runnable the action to run before completing the returned CompletableFuture
     * @return the new CompletableFuture
     */
    public static VertxCompletableFuture<Void> runAsync(Vertx vertx, Runnable runnable) {
        return runAsync(Objects.requireNonNull(vertx).getOrCreateContext(), runnable);
    }

    /**
     * Returns a new CompletableFuture that is asynchronously completed by a task running in the current Vert.x
     * {@link Context} with the value obtained by calling the given Supplier.
     * <p>
     * This method is different from {@link CompletableFuture#supplyAsync(Supplier)} as it does not use a fork join
     * executor, but use the Vert.x context.
     *
     * @param context  the context in which the supplier is executed.
     * @param supplier a function returning the value to be used to complete the returned CompletableFuture
     * @param <T>      the function's return type
     * @return the new CompletableFuture
     */
    public static <T> VertxCompletableFuture<T> supplyAsync(Context context, Supplier<T> supplier) {
        Objects.requireNonNull(supplier);
        VertxCompletableFuture<T> future = new VertxCompletableFuture<>(Objects.requireNonNull(context));
        context.runOnContext(v -> {
            try {
                future.complete(supplier.get());
            } catch (Throwable e) {
                future.completeExceptionally(e);
            }
        });
        return future;
    }

    /**
     * Returns a new CompletableFuture that is asynchronously completed by a task running in the
     * current Vert.x {@link Context} after it runs the given action.
     * <p>
     * This method is different from {@link CompletableFuture#runAsync(Runnable)} as it does not use a fork join
     * executor, but use the Vert.x context.
     *
     * @param context  the context
     * @param runnable the action to run before completing the returned CompletableFuture
     * @return the new CompletableFuture
     */
    public static VertxCompletableFuture<Void> runAsync(Context context, Runnable runnable) {
        Objects.requireNonNull(runnable);
        VertxCompletableFuture<Void> future = new VertxCompletableFuture<>(context);
        context.runOnContext(v -> {
            try {
                runnable.run();
                future.complete(null);
            } catch (Throwable e) {
                future.completeExceptionally(e);
            }
        });
        return future;
    }

    /**
     * Returns a new CompletableFuture that is asynchronously completed by a task running in the worker thread pool of
     * Vert.x
     * <p>
     * This method is different from {@link CompletableFuture#supplyAsync(Supplier)} as it does not use a fork join
     * executor, but the worker thread pool.
     *
     * @param vertx    the Vert.x instance
     * @param supplier a function returning the value to be used to complete the returned CompletableFuture
     * @param <T>      the function's return type
     * @return the new CompletableFuture
     */
    public static <T> VertxCompletableFuture<T> supplyBlockingAsync(Vertx vertx, Supplier<T> supplier) {
        return supplyBlockingAsync(Objects.requireNonNull(vertx).getOrCreateContext(), supplier);
    }

    /**
     * Returns a new CompletableFuture that is asynchronously completed by a action running in the worker thread pool of
     * Vert.x
     * <p>
     * This method is different from {@link CompletableFuture#runAsync(Runnable)} as it does not use a fork join
     * executor, but the worker thread pool.
     *
     * @param vertx    the Vert.x instance
     * @param runnable the action, when its execution completes, it completes the returned CompletableFuture. If the
     *                 execution throws an exception, the returned CompletableFuture is completed exceptionally.
     * @return the new CompletableFuture
     */
    public static VertxCompletableFuture<Void> runBlockingAsync(Vertx vertx, Runnable runnable) {
        return runBlockingAsync(Objects.requireNonNull(vertx).getOrCreateContext(), runnable);
    }

    /**
     * Returns a new CompletableFuture that is asynchronously completed by a action running in the worker thread pool of
     * Vert.x
     * <p>
     * This method is different from {@link CompletableFuture#runAsync(Runnable)} as it does not use a fork join
     * executor, but the worker thread pool.
     *
     * @param context  the Vert.x context
     * @param runnable the action, when its execution completes, it completes the returned CompletableFuture. If the
     *                 execution throws an exception, the returned CompletableFuture is completed exceptionally.
     * @return the new CompletableFuture
     */
    public static VertxCompletableFuture<Void> runBlockingAsync(Context context, Runnable runnable) {
        Objects.requireNonNull(runnable);
        VertxCompletableFuture<Void> future = new VertxCompletableFuture<>(Objects.requireNonNull(context));
        context.executeBlocking(fut -> {
            try {
                runnable.run();
                future.complete(null);
            } catch (Throwable e) {
                future.completeExceptionally(e);
            }
        }, null);
        return future;
    }

    /**
     * Returns a new CompletableFuture that is asynchronously completed by a task running in the worker thread pool of
     * Vert.x
     * <p>
     * This method is different from {@link CompletableFuture#supplyAsync(Supplier)} as it does not use a fork join
     * executor, but the worker thread pool.
     *
     * @param context  the context in which the supplier is executed.
     * @param supplier a function returning the value to be used to complete the returned CompletableFuture
     * @param <T>      the function's return type
     * @return the new CompletableFuture
     */
    public static <T> VertxCompletableFuture<T> supplyBlockingAsync(Context context, Supplier<T> supplier) {
        Objects.requireNonNull(supplier);
        VertxCompletableFuture<T> future = new VertxCompletableFuture<>(context);
        context.<T>executeBlocking(fut -> {
            try {
                fut.complete(supplier.get());
            } catch (Throwable e) {
                fut.fail(e);
            }
        }, ar -> {
            if (ar.failed()) {
                future.completeExceptionally(ar.cause());
            } else {
                future.complete(ar.result());
            }
        });
        return future;
    }

    // ============= Wrapping methods =============

    /**
     * Creates a Vert.x {@link Future} from the given {@link CompletableFuture} (that can be a
     * {@link VertxCompletableFuture}).
     *
     * @param future the future
     * @param <T>    the type of the result
     * @return the Vert.x future completed or failed when the given {@link CompletableFuture} completes or fails.
     */
    public static <T> Future<T> toFuture(CompletableFuture<T> future) {
        Future<T> fut = Future.future();
        Objects.requireNonNull(future).whenComplete((res, err) -> {
            if (err != null) {
                fut.fail(err);
            } else {
                fut.complete(res);
            }
        });
        return fut;
    }

    // ============= Parallel composition methods =============

    /**
     * Returns a new CompletableFuture that is completed when all of the given CompletableFutures complete.  If any of
     * the given CompletableFutures complete exceptionally, then the returned CompletableFuture also does so, with a
     * CompletionException holding this exception as its cause.  Otherwise, the results, if any, of the given
     * CompletableFutures are not reflected in the returned CompletableFuture, but may be obtained by inspecting them
     * individually. If no CompletableFutures are provided, returns a CompletableFuture completed with the value
     * {@code null}.
     * <p>
     * <p>Among the applications of this method is to await completion
     * of a set of independent CompletableFutures before continuing a
     * program, as in: {@code CompletableFuture.allOf(c1, c2, c3).join();}.
     * <p>
     * Unlike the original {@link CompletableFuture#allOf(CompletableFuture[])} this method invokes the dependent
     * stages into the Vert.x context.
     *
     * @param vertx   the Vert.x instance to retrieve the context
     * @param futures the CompletableFutures
     * @return a new CompletableFuture that is completed when all of the given CompletableFutures complete
     * @throws NullPointerException if the array or any of its elements are {@code null}
     */
    public static VertxCompletableFuture<Void> allOf(Vertx vertx, CompletableFuture<?>... futures) {
        CompletableFuture<Void> all = CompletableFuture.allOf(futures);
        return VertxCompletableFuture.from(vertx, all);
    }

    /**
     * Returns a new CompletableFuture that is completed when all of the given CompletableFutures complete.  If any of
     * the given CompletableFutures complete exceptionally, then the returned CompletableFuture also does so, with a
     * CompletionException holding this exception as its cause.  Otherwise, the results, if any, of the given
     * CompletableFutures are not reflected in the returned CompletableFuture, but may be obtained by inspecting them
     * individually. If no CompletableFutures are provided, returns a CompletableFuture completed with the value
     * {@code null}.
     * <p>
     * <p>Among the applications of this method is to await completion
     * of a set of independent CompletableFutures before continuing a
     * program, as in: {@code CompletableFuture.allOf(c1, c2, c3).join();}.
     * <p>
     * Unlike the original {@link CompletableFuture#allOf(CompletableFuture[])} this method invokes the dependent
     * stages into the Vert.x context.
     *
     * @param context the context
     * @param futures the CompletableFutures
     * @return a new CompletableFuture that is completed when all of the given CompletableFutures complete
     * @throws NullPointerException if the array or any of its elements are {@code null}
     */
    public static VertxCompletableFuture<Void> allOf(Context context, CompletableFuture<?>... futures) {
        CompletableFuture<Void> all = CompletableFuture.allOf(futures);
        return VertxCompletableFuture.from(context, all);
    }

    /**
     * Returns a new CompletableFuture that is completed when any of the given CompletableFutures complete, with the
     * same result. Otherwise, if it completed exceptionally, the returned CompletableFuture also does so, with a
     * CompletionException holding this exception as its cause.  If no CompletableFutures are provided, returns an
     * incomplete CompletableFuture.
     * <p>
     * Unlike the original {@link CompletableFuture#allOf(CompletableFuture[])} this method invokes the dependent
     * stages into the Vert.x context.
     *
     * @param vertx   the Vert.x instance to retrieve the context
     * @param futures the CompletableFutures
     * @return a new CompletableFuture that is completed with the result or exception of any of the given
     * CompletableFutures when one completes
     * @throws NullPointerException if the array or any of its elements are {@code null}
     */
    public static VertxCompletableFuture<Object> anyOf(Vertx vertx, CompletableFuture<?>... futures) {
        CompletableFuture<Object> all = CompletableFuture.anyOf(futures);
        return VertxCompletableFuture.from(vertx, all);
    }

    /**
     * Returns a new CompletableFuture that is completed when any of the given CompletableFutures complete, with the
     * same result. Otherwise, if it completed exceptionally, the returned CompletableFuture also does so, with a
     * CompletionException holding this exception as its cause.  If no CompletableFutures are provided, returns an
     * incomplete CompletableFuture.
     * <p>
     * Unlike the original {@link CompletableFuture#allOf(CompletableFuture[])} this method invokes the dependent
     * stages into the Vert.x context.
     *
     * @param context the context
     * @param futures the CompletableFutures
     * @return a new CompletableFuture that is completed with the result or exception of any of the given
     * CompletableFutures when one completes
     * @throws NullPointerException if the array or any of its elements are {@code null}
     */
    public static VertxCompletableFuture<Object> anyOf(Context context, CompletableFuture<?>... futures) {
        CompletableFuture<Object> all = CompletableFuture.anyOf(futures);
        return VertxCompletableFuture.from(context, all);
    }

    // ============= with context methods =============

    /**
     * Creates a new {@link VertxCompletableFuture} using the current context. This method is used to switch between
     * Vert.x contexts.
     *
     * @return the created {@link VertxCompletableFuture}
     */
    public VertxCompletableFuture<T> withContext() {
        Context context = Objects.requireNonNull(Vertx.currentContext());
        return withContext(context);
    }

    /**
     * Creates a new {@link VertxCompletableFuture} using the current context or creates a new one. This method is used
     * to switch between Vert.x contexts.
     *
     * @return the created {@link VertxCompletableFuture}
     */
    public VertxCompletableFuture<T> withContext(Vertx vertx) {
        return withContext(Objects.requireNonNull(vertx).getOrCreateContext());
    }

    /**
     * Creates a new {@link VertxCompletableFuture} using the given context. This method is used to switch between
     * Vert.x contexts.
     *
     * @return the created {@link VertxCompletableFuture}
     */
    public VertxCompletableFuture<T> withContext(Context context) {
        VertxCompletableFuture<T> future = new VertxCompletableFuture<>(Objects.requireNonNull(context));
        whenComplete((res, err) -> {
            if (err != null) {
                future.completeExceptionally(err);
            } else {
                future.complete(res);
            }
        });
        return future;
    }

    /**
     * @return the context associated with the current {@link VertxCompletableFuture}.
     */
    public Context context() {
        return context;
    }

    // ============= Composite Future implementation =============

    @Override
    public <U> VertxCompletableFuture<U> thenApply(Function<? super T, ? extends U> fn) {
        return new VertxCompletableFuture<>(context, super.thenApply(fn));
    }

    @Override
    public <U> VertxCompletableFuture<U> thenApplyAsync(Function<? super T, ? extends U> fn, Executor executor) {
        return new VertxCompletableFuture<>(context, super.thenApplyAsync(fn, executor));
    }

    @Override
    public VertxCompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action, Executor executor) {
        return new VertxCompletableFuture<>(context, super.thenAcceptAsync(action, executor));
    }

    @Override
    public VertxCompletableFuture<Void> thenRun(Runnable action) {
        return new VertxCompletableFuture<>(context, super.thenRun(action));
    }

    @Override
    public VertxCompletableFuture<Void> thenRunAsync(Runnable action, Executor executor) {
        return new VertxCompletableFuture<>(context, super.thenRunAsync(action, executor));
    }

    @Override
    public <U, V> VertxCompletableFuture<V> thenCombine(CompletionStage<? extends U> other,
            BiFunction<? super T, ? super U, ? extends V> fn) {
        return new VertxCompletableFuture<>(context, super.thenCombine(other, fn));
    }

    @Override
    public <U> VertxCompletableFuture<Void> thenAcceptBoth(CompletionStage<? extends U> other,
            BiConsumer<? super T, ? super U> action) {
        return new VertxCompletableFuture<>(context, super.thenAcceptBoth(other, action));
    }

    @Override
    public <U> VertxCompletableFuture<Void> thenAcceptBothAsync(CompletionStage<? extends U> other,
            BiConsumer<? super T, ? super U> action, Executor executor) {
        return new VertxCompletableFuture<>(context, super.thenAcceptBothAsync(other, action, executor));
    }

    @Override
    public VertxCompletableFuture<Void> runAfterBoth(CompletionStage<?> other, Runnable action) {
        return new VertxCompletableFuture<>(context, super.runAfterBoth(other, action));
    }

    @Override
    public VertxCompletableFuture<Void> runAfterBothAsync(CompletionStage<?> other, Runnable action,
            Executor executor) {
        return new VertxCompletableFuture<>(context, super.runAfterBothAsync(other, action, executor));
    }

    @Override
    public <U> VertxCompletableFuture<U> applyToEither(CompletionStage<? extends T> other,
            Function<? super T, U> fn) {
        return new VertxCompletableFuture<>(context, super.applyToEither(other, fn));
    }

    @Override
    public <U> VertxCompletableFuture<U> applyToEitherAsync(CompletionStage<? extends T> other,
            Function<? super T, U> fn, Executor executor) {
        return new VertxCompletableFuture<>(context, super.applyToEitherAsync(other, fn, executor));
    }

    @Override
    public VertxCompletableFuture<Void> acceptEither(CompletionStage<? extends T> other,
            Consumer<? super T> action) {
        return new VertxCompletableFuture<>(context, super.acceptEither(other, action));
    }

    @Override
    public VertxCompletableFuture<Void> acceptEitherAsync(CompletionStage<? extends T> other,
            Consumer<? super T> action, Executor executor) {
        return new VertxCompletableFuture<>(context, super.acceptEitherAsync(other, action, executor));
    }

    @Override
    public VertxCompletableFuture<Void> runAfterEither(CompletionStage<?> other, Runnable action) {
        return new VertxCompletableFuture<>(context, super.runAfterEither(other, action));
    }

    @Override
    public VertxCompletableFuture<Void> runAfterEitherAsync(CompletionStage<?> other, Runnable action,
            Executor executor) {
        return new VertxCompletableFuture<>(context, super.runAfterEitherAsync(other, action, executor));
    }

    @Override
    public <U> VertxCompletableFuture<U> thenCompose(Function<? super T, ? extends CompletionStage<U>> fn) {
        return new VertxCompletableFuture<>(context, super.thenCompose(fn));
    }

    @Override
    public VertxCompletableFuture<T> whenComplete(BiConsumer<? super T, ? super Throwable> action) {
        return new VertxCompletableFuture<>(context, super.whenComplete(action));
    }

    @Override
    public VertxCompletableFuture<T> whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action,
            Executor executor) {
        return new VertxCompletableFuture<>(context, super.whenCompleteAsync(action, executor));
    }

    @Override
    public <U> VertxCompletableFuture<U> handle(BiFunction<? super T, Throwable, ? extends U> fn) {
        return new VertxCompletableFuture<>(context, super.handle(fn));
    }

    @Override
    public <U> VertxCompletableFuture<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn,
            Executor executor) {
        return new VertxCompletableFuture<>(context, super.handleAsync(fn, executor));
    }

    @Override
    public <U> VertxCompletableFuture<U> thenApplyAsync(Function<? super T, ? extends U> fn) {
        return new VertxCompletableFuture<>(context, super.thenApplyAsync(fn, executor));
    }

    @Override
    public VertxCompletableFuture<Void> thenAccept(Consumer<? super T> action) {
        return new VertxCompletableFuture<>(context, super.thenAccept(action));
    }

    @Override
    public VertxCompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action) {
        return new VertxCompletableFuture<>(context, super.thenAcceptAsync(action, executor));
    }

    @Override
    public VertxCompletableFuture<Void> thenRunAsync(Runnable action) {
        return new VertxCompletableFuture<>(context, super.thenRunAsync(action, executor));
    }

    @Override
    public <U, V> VertxCompletableFuture<V> thenCombineAsync(CompletionStage<? extends U> other,
            BiFunction<? super T, ? super U, ? extends V> fn) {
        return new VertxCompletableFuture<>(context, super.thenCombineAsync(other, fn, executor));
    }

    @Override
    public <U> VertxCompletableFuture<Void> thenAcceptBothAsync(CompletionStage<? extends U> other,
            BiConsumer<? super T, ? super U> action) {
        return new VertxCompletableFuture<>(context, super.thenAcceptBothAsync(other, action, executor));
    }

    @Override
    public VertxCompletableFuture<Void> runAfterBothAsync(CompletionStage<?> other, Runnable action) {
        return new VertxCompletableFuture<>(context, super.runAfterBothAsync(other, action, executor));
    }

    @Override
    public <U> VertxCompletableFuture<U> applyToEitherAsync(CompletionStage<? extends T> other,
            Function<? super T, U> fn) {
        return new VertxCompletableFuture<>(context, super.applyToEitherAsync(other, fn, executor));
    }

    @Override
    public VertxCompletableFuture<Void> acceptEitherAsync(CompletionStage<? extends T> other,
            Consumer<? super T> action) {
        return new VertxCompletableFuture<>(context, super.acceptEitherAsync(other, action, executor));
    }

    @Override
    public VertxCompletableFuture<Void> runAfterEitherAsync(CompletionStage<?> other, Runnable action) {
        return new VertxCompletableFuture<>(context, super.runAfterEitherAsync(other, action, executor));
    }

    @Override
    public <U> VertxCompletableFuture<U> thenComposeAsync(Function<? super T, ? extends CompletionStage<U>> fn) {
        return new VertxCompletableFuture<>(context, super.thenComposeAsync(fn, executor));
    }

    @Override
    public <U> VertxCompletableFuture<U> thenComposeAsync(Function<? super T, ? extends CompletionStage<U>> fn,
            Executor executor) {
        return new VertxCompletableFuture<>(context, super.thenComposeAsync(fn, executor));
    }

    public <U, V> VertxCompletableFuture<V> thenCombineAsync(CompletionStage<? extends U> other,
            BiFunction<? super T, ? super U, ? extends V> fn, Executor executor) {
        return new VertxCompletableFuture<>(context, super.thenCombineAsync(other, fn, executor));
    }

    @Override
    public VertxCompletableFuture<T> whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action) {
        return new VertxCompletableFuture<>(context, super.whenCompleteAsync(action, executor));
    }

    @Override
    public <U> VertxCompletableFuture<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn) {
        return new VertxCompletableFuture<>(context, super.handleAsync(fn, executor));
    }

    @Override
    public VertxCompletableFuture<T> toCompletableFuture() {
        return this;
    }

    // ============= other instance methods =============

    /**
     * Creates a new {@link Future} object completed / failed when the current {@link VertxCompletableFuture} is
     * completed successfully or not.
     *
     * @return the {@link Future}.
     */
    public Future<T> toFuture() {
        return VertxCompletableFuture.toFuture(this);
    }

    private void complete(T result, Throwable error) {
        if (error == null) {
            super.complete(result);
        } else {
            super.completeExceptionally(error);
        }
    }

    private void completeFromAsyncResult(AsyncResult<T> ar) {
        if (ar.succeeded()) {
            super.complete(ar.result());
        } else {
            super.completeExceptionally(ar.cause());
        }
    }

}