I'm trying to understand CompletableFuture
and how I can utilise it to build an object with information obtained from several endpoints. I've come across a few examples but none are quite tailored to my problem. For example, this one is running the same method in parallel to get a list of strings where I want to run multiple methods in parallel to build and return an object.
I've created a simple DTO for an employee:
@Builder
@Data
@AllArgsConstructor
public class EmployeeDTO {
private String name;
private String accountNumber;
private int salary;
}
I've created a service to mimic calls to three separate APIs to set the values of the DTO with a considerable wait time:
public class EmployeeService {
public EmployeeDTO setName() {
try {
Thread.sleep(10 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return EmployeeDTO.builder().name("John Doe").build();
}
public EmployeeDTO setAccountNumber() {
try {
Thread.sleep(10 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return EmployeeDTO.builder().accountNumber("1235").build();
}
public EmployeeDTO setSalary() {
try {
Thread.sleep(10 * 1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return EmployeeDTO.builder().salary(100000).build();
}
}
I can supplyAsync
all three of the methods and then run allOf
but it doesn't do anything:
private void run() {
EmployeeService employeeService = new EmployeeService();
CompletableFuture<EmployeeDTO> employeeCfWithName = CompletableFuture
.supplyAsync(employeeService::setName);
CompletableFuture<EmployeeDTO> employeeCfWithAccountNumber = CompletableFuture
.supplyAsync(employeeService::setAccountNumber);
CompletableFuture<EmployeeDTO> employeeCfWithSalary = CompletableFuture
.supplyAsync(employeeService::setSalary);
CompletableFuture allCompletableFutures = CompletableFuture.allOf(employeeCfWithName, employeeCfWithAccountNumber, employeeCfWithSalary);
}
How can I combine the results into one EmployeeDTO?
You will have to combine the results of the three CompletableFuture
s into a single EmployeeDTO
. This is not magically done by allOf
.
Try something like this (untested):
CompletableFuture allCompletableFutures = CompletableFuture.allOf(
employeeCfWithName, employeeCfWithAccountNumber, employeeCfWithSalary);
// Wait for all three to complete.
allCompletableFutures.get();
// Now join all three and combine the results.
EmployeeDTO finalResult = EmployeeDTO.builder()
.name(new employeeCfWithName.join())
.accountNumber(new employeeCfWithAccountNumber.join())
.salary(new employeeCfWithSalary.join())
.build();
This looks a little bit silly. We use a builder in every method just to combine their results using a fourth builder.