Using CompletableFuture to build an object with multiple methods

Nanor :

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?

user11044402 :

You will have to combine the results of the three CompletableFutures 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.

Guess you like

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