Reputation: 2578
I have a method that is used in my Java Vert.x project which calls another service using WebClient
. I want to save the result of that call in a JsonObject
and return it. I'm assuming that I need to use futures for this, but when I run GetItemsService.retrieveItems
, aside from my "print future below" message all I see in the console is Future{unresolved}
.
How can I save the result from my GetItemsManager.getItems
web client call in a variable?
public class GetItemsManager {
public Future<JsonObject> getItems(Future<JsonObject> future, Vertx vertx, RoutingContext routingContext) {
WebClient webClient = WebClient.create(vertx);
HttpServerResponse response = routingContext.response();
JsonObject data = new JsonObject();
response.setChunked(true);
response.putHeader("content-type", "text/plain");
response.putHeader("Access-Control-Allow-Origin", "*");
webClient.post(80, Constants.API_URL, "/items")
.as(BodyCodec.jsonArray())
.putHeader("Accept", "application/json")
.putHeader("Content-Type", "application/json")
.putHeader("ugws7", Constants.SERVICES_URL)
.sendJsonObject(new JsonObject().put("mutator", "*"), ar -> {
if (ar.succeeded()) {
HttpResponse<JsonArray> result = ar.result();
JsonArray body = result.body();
data.put("data", body.getJsonObject(0));
future.complete(data);
} else {
future.fail(new JsonObject().put("error", ar.cause().getMessage()).encode());
}
});
return future;
}
}
public class GetItemsService {
public void retrieveItems(Vertx vertx, RoutingContext routingContext) {
Future<JsonObject> future = Future.future();
new GetItemsManager().getItems(future, vertx, routingContext);
String jsonObject = future.toString();
System.out.println("print future below");
System.out.println(jsonObject);
}
}
UPDATE
As per Peter's answer, I've tried to update my code with the following:
public class GetItemsService {
public void retrieveItems(Vertx vertx, RoutingContext routingContext) {
Future<JsonObject> future = Future.future();
new GeItemsManager().getItems(future, vertx, routingContext);
String jsonObject;
Future<JsonObject> f = future.setHandler(handler -> {
handler.result();
});
System.out.println("Print future below");
System.out.println(f);
}
}
I still cannot assign the result of the call to a variable (f
).
Upvotes: 3
Views: 3271
Reputation: 3040
I hope this helps i tried to add useful comments to your code.
GetItemsManager
public class GetItemsManager {
public Future<JsonObject> getItems(Vertx vertx, RoutingContext routingContext) {
//Note1: you can create the future here, no need to pass as a parameter
Future<JsonObject> future = Future.future();
...
webClient.post(80, Constants.API_URL, "/items")
...
.sendJsonObject(new JsonObject().put("mutator", "*"), ar -> {
if (ar.succeeded()) {
...
future.complete(data);
} else {
future.fail(new JsonObject().put("error", ar.cause().getMessage()).encode());
}
});
return future;
}
}
GetItemsService
public class GetItemsService {
public void retrieveItems(Vertx vertx, RoutingContext routingContext) {
new GetLocationsManager().getItems(vertx, routingContext) // returns Future<JsonObject>
.setHandler(handler -> {
//Note2: this codeblock is executed when your future is completed (or failed)
if(handler.succeeded()){
//Note3: handler.result() contains the result from the getItems call (future.complete(data))
JsonObject items = handler.result();
doSomethingWithTheItems(items);
String itemsEncodedToString = items.encode();
// serve the response
routingContext.response().end(itemsEncodedToString);
}else{
// serve error response
routingContext.response().end("something terrible happened" + handler.cause());
}
});
}
public void doSomethingWithTheItems(JsonObject items){
// do something here with your items
}
}
// Option 2 if you want to execute some other async method
public class GetItemsService {
public void retrieveItems(Vertx vertx, RoutingContext routingContext) {
new GetLocationsManager().getItems(vertx, routingContext);
.compose(this::doSomethingAsyncWithTheItems)
.setHandler(handler -> {
if(handler.succeeded()){
//Note4: handler.result() contains the result from the doSomethingAsyncWithTheItems call (future.complete(...))
JsonObject didSomethingWithTheItems = handler.result();
routingContext.response().end(didSomethingWithTheItems.encode());
}else{
// serve error response
routingContext.response().end("something terrible happened");
}
});
}
public Future<JsonObject> doSomethingAsyncWithTheItems(JsonObject items){
Future<JsonObject> future = Future.future();
otherAsyncCallThatReturnsAFuture.setHandler(handler -> {
if(handler.succeeded()){
future.complete(...)
}else{
future.fail(...)
}
})
return future;
}
}
Upvotes: 4
Reputation: 3040
Try something like
public class GetItemsService {
public void retrieveItems(Vertx vertx, RoutingContext routingContext) {
Future<JsonObject> future = Future.future();
new GetLocationsManager().getItems(future, vertx, routingContext);
future.setHandler(h ->{
routingContext.response().end(h.result().encode());
});
}
}
Upvotes: 4