Aliaksei
Aliaksei

Reputation: 1457

CompletableFuture wrapper

I have async method

asyncClass.getChild("test", listChild -> {
  if (listChild.isOk()) {
  List<String> list = listChild.isSuccess().getData()
  }
  return null;
});

How I can wrap this async call in CompletableFuture?

final CompletableFuture<List<String>> future = new CompletableFuture<>();
asyncClass.getChild("test", listChild -> {
  if (listChild.isOk()) {
    future.complete(listChild.isSuccess().getData());
  }
  return null;
});
return future;

Everything works fine, but I want everything to work in a separate thread calls

interface AsyncFS {
    fun getChild(path: String, onResult: (Result<List<String>>) -> Unit)
}

Upvotes: 1

Views: 4606

Answers (3)

Didier L
Didier L

Reputation: 20579

Change your getChild() method to return a CompletableFuture<ListChild> instead of taking a callback as parameter.

Without the actual code, I cannot tell exactly how this must be done, but basically the code would look like

CompletableFuture<ListChild> result = new CompletableFuture<>();
processAsynchronously(path, result);
return result;

where processAsynchronously() performs the asynchronous computation, and at some point calls result.complete(listChild).

The caller will then be able to easily chain calls like

CompletableFuture<List<String>> result = asyncClass.getChild("test")
          .thenAcceptAsync(listChild -> {
              if (listChild.isOk()) {
                  return listChild.isSuccess().getData()
              }
              return null;
          }, executor);

or any other processing using any executor he wants.

As you see, this will be much more flexible than forcing a particular type of callback.

Upvotes: 0

mattmess1221
mattmess1221

Reputation: 4444

Supply a Runnable or Supplier as an argument to CompletableFuture.runAsync() or supplyAsync()

return CompletableFuture.runAsync(() -> {
    doSomething();
}, optionalExecutor);

Upvotes: 0

ernest_k
ernest_k

Reputation: 45319

It seems that asyncClass.getChild is executed asynchronously (as it takes a callback). If that's the case, then your current implementation is enough (except for the correction below).

asyncClass.getChild("test", listChild -> {
  if (listChild.isOk()) {
    future.complete(listChild.isSuccess().getData());
  } else {
      future.complete(null); //you need to do this
      //or future.completeExceptionally(exception) if this is a failure
  }
});

If you want getChild to run in a separate thread, then I'd strongly suggest you redesign the method to make it return List<String> instead of taking a callback. This design makes it awkward to run getChild asynchronously.

interface AsyncFS {
    fun getChild(path: String): List<String> //don't trust my syntax
}

And then run it asynchronously in this way:

CompletableFuture<List<String>> future = 
    CompletableFuture.supplyAsync(() -> asyncClass.getChild("test"));
return future;

Upvotes: 3

Related Questions