1

I want to return an autocloseable object inside a CompletableFuture and use it in whenComplete without going to close it manually later.

This is the code that I've tried, but of course it won't work because it closes automatically when I return Jedis object. I haven't got any other ideas.

@Override
    public CompletableFuture<Jedis> execute() {
       if(!isServiceActive()) return CompletableFuture.completedFuture(null);
       return CompletableFuture.supplyAsync(() -> {
           try (Jedis jedis = pool.getResource()) {
              return jedis;
          } catch (RuntimeException e) {
              logger.severe("Impossibile ottenere una nuova risorsa Jedis!", e);
              throw new CompletionException(e);
          }
      }, executor);
  }
2
  • When do you want it to be closed? What does your method execute? Commented Jan 6, 2023 at 21:29
  • That's not possible. You either consume your autoclosable in the try-with-resources block you declare it, or you return it and the client code has to close it. It does seem like a questionable design decision to return a closable in a future tbh. Commented Jan 6, 2023 at 21:37

1 Answer 1

2

In general, this is not possible; CompletableFuture is not designed for this. As you've noted, you can't close the resource before completing the future, because then it will be closed before any consumers get to act on it. That means the consumer will have to be responsible for closing the resource.

However, if your goal is to only need that Jedis instance in the one whenComplete call, then perhaps there is an alternative solution. Either modify execute() or create a new method that looks something like the following:

<T> CompletableFuture<T> execute(Function<? super Jedis, ? extends T> func) {
    if (!isServiceActive()) return CompletableFuture.completedFuture(null);
    return CompletableFuture.supplyAsync(() -> {
        try (Jedis jedis = pool.getResource()) {
            return func.apply(jedis);
        } catch (Exception ex) {
            // log exception
            throw new CompletionException(ex);
        }
    }), executor);
}

The Jedis instance is closed by the time the future completes, but it still lets you do the needed work in the Function implementation. Using it would look like:

execute(jedis -> {
    // use Jedis instance
    return result;
})
.whenComplete((result, error) -> {
    if (error != null) {
        // process error
    } else {
       // process result
    }
});

Though I don't know if your code can be modified to use this approach, as I notice your execute() method is an override (whether from a class/interface you control, I don't know). But even if you can't modify execute() directly or supply an overload feasibly, you might still be able to create a utility method that does something similar to the above.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.