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.
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
orFuture
. In the latter case, you may declare the more specificListenableFuture
orCompletableFuture
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.