I currently want to fetch details of users in an asynchronous way and convert those details into an excel file.
Here is the method that fetches the details in batches from the db created in the repository.
public CompletableFuture<ArrayList<UserProfile>> fetchUserDetailsBatches(Bson filter){
return CompletableFuture.supplyAsync( () -> {
Bson projection = Projections.fields(Projections.exclude("roleGroup", "roles"));
return this.userCollection.find(filter).projection(projection).skip(1).limit(1000).
into(new ArrayList<>());
});
}
Here is the class that converts to excel file. It was working pretty fine before now till when I was using Stream before I changed to CompleteFuture.
public static InputStream writeToExcel(CompletableFuture<ArrayList<UserProfile>> data) throws Exception {
//Blank workbook
try (XSSFWorkbook workbook = new XSSFWorkbook()) {
//Create a blank sheet
XSSFSheet sheet = workbook.createSheet("userDetails report");
AtomicInteger rowNum = new AtomicInteger(1);
AtomicBoolean isHeaderSet = new AtomicBoolean(false);
data.forEach(userProfile -> {
if (!isHeaderSet.get()){
createHeader(userProfile, sheet);
isHeaderSet.set(true);
}
XSSFRow row = sheet.createRow(rowNum.getAndIncrement());
ObjectMapper mapObject = new ObjectMapper();
Map<String, Object> mapObj = mapObject.convertValue(userProfile, Map.class);
AtomicInteger cellNum = new AtomicInteger();
mapObj.forEach((key, value) -> {
XSSFCell cell = row.createCell(cellNum.getAndIncrement());
cell.setCellValue(key);
if (value instanceof Integer)
cell.setCellValue((Integer) value);
else if (value instanceof BigDecimal)
cell.setCellValue(((BigDecimal) value).doubleValue());
else if (value instanceof Long)
cell.setCellValue((Long) value);
else cell.setCellValue(String.valueOf(value));
});
});
try {
//Write the workbook in file system
ByteArrayOutputStream bos = new ByteArrayOutputStream();
workbook.write(bos);
byte[] barray = bos.toByteArray();
InputStream is = new ByteArrayInputStream(barray);
log.info("userDetails.csv written successfully on disk.");
return is;
} catch (Exception e) {
e.printStackTrace();
throw new Exception(e.getMessage());
}
} catch (IOException e) {
e.printStackTrace();
throw new Exception(e.getMessage());
}
}
The error is that it cannot resolve forEach
method in CompleteFuture class thus, the instance of the user class I am passing here createHeader(userProfile, sheet);
is also throwing error as an Object was expected and I provided a lambda which is coming from the CompleteFuture. What do I do? Was the best way to solve this problem?
CodePudding user response:
You need to wait for the Future(here your parameter data) to be loaded, you an do it async or you can just call data.get() and then start using '.foreach', it stops the current thread as long as it takes to complete the future.
Edit: Just replace the lower method with this:
public static InputStream writeToExcel(CompletableFuture<ArrayList<UserProfile>> data) throws Exception {
//Blank workbook
try (XSSFWorkbook workbook = new XSSFWorkbook()) {
//Create a blank sheet
XSSFSheet sheet = workbook.createSheet("userDetails report");
AtomicInteger rowNum = new AtomicInteger(1);
AtomicBoolean isHeaderSet = new AtomicBoolean(false);
data.get().forEach(userProfile -> {
if (!isHeaderSet.get()){
createHeader(userProfile, sheet);
isHeaderSet.set(true);
}
XSSFRow row = sheet.createRow(rowNum.getAndIncrement());
ObjectMapper mapObject = new ObjectMapper();
Map<String, Object> mapObj = mapObject.convertValue(userProfile, Map.class);
AtomicInteger cellNum = new AtomicInteger();
mapObj.forEach((key, value) -> {
XSSFCell cell = row.createCell(cellNum.getAndIncrement());
cell.setCellValue(key);
if (value instanceof Integer)
cell.setCellValue((Integer) value);
else if (value instanceof BigDecimal)
cell.setCellValue(((BigDecimal) value).doubleValue());
else if (value instanceof Long)
cell.setCellValue((Long) value);
else cell.setCellValue(String.valueOf(value));
});
});
try {
//Write the workbook in file system
ByteArrayOutputStream bos = new ByteArrayOutputStream();
workbook.write(bos);
byte[] barray = bos.toByteArray();
InputStream is = new ByteArrayInputStream(barray);
log.info("userDetails.csv written successfully on disk.");
return is;
} catch (Exception e) {
e.printStackTrace();
throw new Exception(e.getMessage());
}
} catch (IOException e) {
e.printStackTrace();
throw new Exception(e.getMessage());
}
}