Optimal way to resolve/handle List<CompletableFuture<List<Object>>> in Java 8

user1613360 :

Code: Spring bean snippet:

@Component
class myService {

 private CSVFileProcessor csvFileProcessor;

 public myService(CSVFileProcessor csvFileProcessor) {

         this.csvFileProcessor=csvFileProcessor;

    }

/* input: List of promises/futures obtained by reading 
 *   csv files from S3 bucket
 * 
 * output: List of promises of list of parsed csv 
 *   documents converted to POJO's of type Document
 *  
 *
 */
  @Async
  public List<CompletableFuture<List<Document>>> createDocumentObjects(
      List<CompletableFuture<ResponseBytes<GetObjectResponse>>> documentsFuture) {

 return documentsFuture.stream().map(myDocument-> myDocument.thenCompose(document-> CompletableFuture.supplyAsync(
                 () ->   csvFileProcessor.parseObjects(document)))).collect(Collectors.toList());

}

So in the service layer I inject the above bean and try to do something like:

List<CompletableFuture<List<Document>>> listOfPromises= injectedBean.createDocumentObjects(input);

//The below code throws NPE(Null pointer exception) 
List<List<Document>> myDocuments =listOfPromises.stream().map(CompletableFuture::join).collect(Collectors.toList());

listOfPromises seems to be null. I checked the logs for csvFileProcessor class and inputs are getting processed as expected. Tried adding exceptionally and handle blocks to the future call still no exception thrown from those places apart from the same NPE while trying to resolve the promise.

I'm sure I am missing something trivial and any guidance in the right direction would be very helpful.

Didier L :

As per the @Async documentation:

In terms of target method signatures, any parameter types are supported. However, the return type is constrained to either void or Future. In the latter case, you may declare the more specific ListenableFuture or CompletableFuture types which allow for richer interaction with the asynchronous task and for immediate composition with further processing steps.

Your method returns neither of those, so Spring does not know what to do with it. Unfortunately, instead of giving an error, it accepts the call, defers the method execution to a separate thread and immediately returns null.

It seems however that you don't really need @Async here, since your method is handling the asynchronous execution itself (through composition and supplyAsync()), so you can probably just remove the annotation to fix the problem.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=31825&siteId=1