Skip to content
Advertisement

How to move from deprecated Task to ApiFuture for firebase admin SDK 5.4 and above

I’m just trying to solve the deprecation notes from my Java code of new firebase-admin SDK, the code is written in version 5.3.1 but after upgrading the version into 5.5.0 the deprecation notes appeared, here is a sample of my code:

Using FirebaseAuth (deprecatation on: Task, addOnSuccessListener and addOnFailureListener) :

private CompletableFuture<FirebaseToken> getDecryptedTokenCompletableFuture(String firebaseTokenString) {
        CompletableFuture<FirebaseToken> tokenFuture = new CompletableFuture<>();
        Task<FirebaseToken> tokenTask = FirebaseAuth.getInstance(firebaseApp).verifyIdToken(firebaseTokenString);
        tokenTask.addOnSuccessListener(tokenFuture::complete);
        tokenTask.addOnFailureListener(exception -> tokenFuture.completeExceptionally(new AuthorizationException("Failed to verify token", exception)));
        return tokenFuture;
    }

And for FirebaseDatabase (deprecatation on: Task, addOnSuccessListener, addOnFailureListener, updateChildren and removeValue) :

public static <T> CompletableFuture<T> toCompletableFuture(Task<T> task) {
    CompletableFuture<T> future = new CompletableFuture<>();
    task.addOnCompleteListener(result -> {
        future.complete(result.getResult());
    }).addOnFailureListener(future::completeExceptionally);
    return future;
}

/**
 * @param updatedParams if null it will removed child
 * @param path          path to update
 * @return void when complete
 */
public CompletableFuture<Void> updateObjectData(Map<String, Object> updatedParams, String path) {
    if (updatedParams == null) {
        return removeObjectData(path);
    }
    logger.debug("Update ObjectData in firebase of ref ({}) with data: {}", path, updatedParams.toString());
    DatabaseReference child = this.getUserDataReference().child(path);
    return toCompletableFuture(child.updateChildren(updatedParams));
}

/**
 * @param path path to of node to remove
 * @return void when complete
 */
public CompletableFuture<Void> removeObjectData(String path) {
    logger.debug("Remove ObjectData in firebase of ref ({})", path);
    DatabaseReference child = this.getUserDataReference().child(path);
    return toCompletableFuture(child.removeValue());
}

The deprecation note saying I have to use ApiFuture as what the release notes saying: https://firebase.google.com/support/release-notes/admin/java

And inside source, as for example:

  /**
   * Similar to {@link #updateChildrenAsync(Map)} but returns a Task.
   *
   * @param update The paths to update and their new values
   * @return The {@link Task} for this operation.
   * @deprecated Use {@link #updateChildrenAsync(Map)}
   */

And

/**
 * Represents an asynchronous operation.
 *
 * @param <T> the type of the result of the operation
 * @deprecated {@code Task} has been deprecated in favor of
 *     <a href="https://googleapis.github.io/api-common-java/1.1.0/apidocs/com/google/api/core/ApiFuture.html">{@code ApiFuture}</a>.
 *     For every method x() that returns a {@code Task<T>}, you should be able to find a
 *     corresponding xAsync() method that returns an {@code ApiFuture<T>}.
 */

Advertisement

Answer

Almost 2 years, but need to add my answers, current answers gave me a guide but were not a full solution, so Kudos for @Enylton Machado and @Hiranya Jayathilaka it is still good to refer to their answers, give them upvotes.

Currently, I did change toCompletableFuture to:

public <T> CompletableFuture<T> toCompletableFuture(ApiFuture<T> apiFuture) {
    final CompletableFuture<T> future = new CompletableFuture<>();
    apiFuture.addListener(() -> {
        try {
            future.complete(apiFuture.get());
        } catch (InterruptedException | ExecutionException ex) {
            logger.error(ex.getMessage());
            future.completeExceptionally(ex);
        }
    }, executionContext);
    return future;
}

Where executionContext got injected in the constructor, since I’m using Play Framework, or you can initialize your own using Executors.newFixedThreadPool(10) as for example! but you need to handle shutting down it and other stuff, more details can be learned from here ExecutorService in Java or A Guide to the Java ExecutorService.

So when I do call like this.getUserDataReference().child(path).push().setValueAsync(value), I do call it like:

public CompletableFuture<String> pushDataToArray(String path, Map<String, Object> paramsToAdd) {
    final DatabaseReference databaseReference = getUserDataReference().child(path).push();
    paramsToAdd.put("createdAt", ServerValue.TIMESTAMP);

    return toCompletableFuture(databaseReference.setValueAsync(paramsToAdd), this.executionContext)
            .thenApply(voidResult -> databaseReference.getKey());
}

Edit: if you prefer use ApiFutures:

public <T> CompletableFuture<T> toCompletableFuture(ApiFuture<T> apiFuture) {
    final CompletableFuture<T> future = new CompletableFuture<>();
    ApiFutures.addCallback(apiFuture, new ApiFutureCallback<T>() {
        @Override
        public void onFailure(Throwable t) {
            future.completeExceptionally(t);
        }

        @Override
        public void onSuccess(T result) {
            try {
                future.complete(apiFuture.get());
            } catch (InterruptedException | ExecutionException ex) {
                logger.error(ex.getMessage());
                future.completeExceptionally(ex);
            }
        }
    }, executionContext);
    return future;
}
Advertisement