import java.util.ArrayList;
import java.util.concurrent.CompletionStage;
import play.libs.concurrent.HttpExecutionContext;
import play.libs.ws.WSClient;
import play.libs.ws.WSRequest;
import play.libs.ws.WSResponse;
class CustomerDetailedData {
private String id;
private String role;
private String customerData;
}
class CustomRestClient {
private final WSClient ws;
private final HttpExecutionContext httpExecutionContext;
@javax.inject.Inject
public CustomRestClient(final WSClient ws, final HttpExecutionContext httpExecutionContext) {
this.ws = ws;
this.httpExecutionContext = httpExecutionContext;
}
public CompletionStage<RestResponse> get(final RestMessage restMessage) {
return ws.url(restMessage).get()
.thenApplyAsync(wsResponse -> {
return new RestResponse().setMsgBody(Json.parse(wsResponse.getBody()));
}, httpExecutionContext.current());
}
}
public class CompletionStagesExample {
@Inject
private CustomRestClient customRestClient;
public static CompletionStage<CustomerDetailedData > getData(String url, String role, String id) {
return customRestClient.get(new RestMessage(url, role, id))
.thenApply(restResponse -> {
CustomerDetailedData customerData = convertToCustomerData(restResponse);
//here the role arg does not match response received by the get method
//(we got here response for roleC, but role argument of getData method has "roleB" value on the current step)
customerData.setRole(role);
return customerData;
});
}
public static void main(String[] args) {
final List<CompletableFuture<CustomerDetailedData>> futures = new ArrayList<>();
futures.add(getData("url for role A", "RoleA", "123123a").toCompletableFuture());
futures.add(getData("url for role B", "RoleB", "123123b").toCompletableFuture());
futures.add(getData("url for role C", "RoleC", "123123c").toCompletableFuture());
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
.thenApply(aVoid -> {
final List<CustomerDetailedData> detailList = new ArrayList<>();
futures.stream()
.map(CompletableFuture::join)
.forEach(System.out::println);
});
}
}
输出可能如下所示(每次都可能不同):
[id = "123123a", role = "roleB", customerData = "服务器返回的角色 A 的一些数据"], [id = "123123b", role = "roleC", customerData = "角色 B 返回的一些数据server"], [id = "123123c", role = "roleA", customerData = "服务器返回的角色 C 的一些数据"]
预期结果:
[id = "123123a", role = "roleA", customerData = "服务器返回的角色 A 的一些数据"], [id = "123123b", role = "roleB", customerData = "角色 B 返回的一些数据server"], [id = "123123c", role = "roleC", customerData = "服务器返回的角色 C 的一些数据"]
我建议在 thenApply 主体中的 getData 方法中的角色搞砸(不匹配 id),因为 thenApply 访问了 getData 方法参数的错误示例(它们正在更改顺序,因为 thenApply 在 WSRequest 返回的另一个线程中执行)。
请看我在代码中的评论。
有谁知道Java是否保证放置在thenApply中的代码总是可以访问方法参数的正确示例(在我的例子中是getData方法的参数)?