0

I have this bit of code:

public static void main(String[] args) throws UnirestException {
    ArrayList<Stock> listStock 
             = getAllAvailableStocks("https://api.iextrading.com/1.0/ref-data/symbols");
    //doing more actions after the one before, using the data from the listStock etc.
}


private static ArrayList<Stock> getAllAvailableStocks(String url) {
    ArrayList<Stock> stocks = new ArrayList<Stock>();
    Future<HttpResponse<JsonNode>> future = Unirest.get(url)
              .header("accept", "application/json")
              .asJsonAsync(new Callback<JsonNode>() {
                public void failed(UnirestException e) {
                    System.out.println("The request has failed");
                }

                public void completed(HttpResponse<JsonNode> response) {
                     ObjectMapper objectMapper = new ObjectMapper();
                    try {
                        listStock = objectMapper.readValue(response.getRawBody(), new TypeReference<List<Stock>>(){});
                    } catch (Exception e) {
                        System.out.println("all is fucked");
                    }   
                    return listStock;
                }

                public void cancelled() {
                    System.out.println("The request has been cancelled");
                }

            });
}

I am a newbie in java, i want to do the following:

1) I want to do async call to get and extract a list of stocks, only after the request completed i want to do the next things in the main method.

2) How do i extract data from the method i built so i can use the data outside of the method?

3) If i need to do the following:

getAllAvailableStocks("https://api.iextrading.com/1.0/ref-data/symbols",new Callback<JsonNode>() {
            public void failed(UnirestException e) {
                System.out.println("The request has failed");
            }

        public void completed(HttpResponse<JsonNode> response) {
             ArrayList<Stock> listStock = new ArrayList<Stock>();
             ObjectMapper objectMapper = new ObjectMapper();
             int code = response.getStatus();
             System.out.println(code);
            try {
                listStock = objectMapper.readValue(response.getRawBody(), new TypeReference<List<Stock>>(){});
            } catch (Exception e) {

            }   
            System.out.println(listStock);
        }

        public void cancelled() {
            System.out.println("The request has been cancelled");
        }

    });
}



private static Future<HttpResponse<JsonNode>> getAllAvailableStocks(String url,Callback<JsonNode> cb) {
    return Unirest.get(url)
              .header("accept", "application/json")
              .asJsonAsync(cb);
}

Or something of that sort, it makes the code horrible, and when i want to do much more async requests after, i have a callback hell here, is there any way to avoid it? what are my options here?

totothegreat
  • 1,633
  • 4
  • 27
  • 59
  • You'll need to do call the next piece of logic from within the `completed` block, after `listStock` is populated. It's pretty rare to write everything as static methods, so I'm thinking you're probably a real newbie to java - if so, I'd suggest you do a bit more digging into basic java before you start looking at futures and async, if not, my apologies. – GregHNZ Jul 21 '18 at 07:46

1 Answers1

1

I think your are mixing up asnychronous and synchronous.

If you

want to do async call to get and extract a list of stocks, only after the request completed I want to do the next things in the main method

then you actually want to perform a synchronous call.

An asynchronous call would be to perform the request, then doing other things (not related to the request) and at some point in the future you get the result of the request and handle it.

To perform a synchronous call, which is probably what you want, try to adapt your code like this:

private static ArrayList<Stock> getAllAvailableStocks(String url) {
    ArrayList<Stock> stocks = new ArrayList<Stock>();
    Future<HttpResponse<JsonNode>> future = Unirest.get(url)
              .header("accept", "application/json")
              .asJsonAsync(new Callback<JsonNode>() {
                public void failed(UnirestException e) {
                    System.out.println("The request has failed");
                }

                public void completed(HttpResponse<JsonNode> response) {
                    System.out.println("The request succeeded");
                }

                public void cancelled() {
                    System.out.println("The request has been cancelled");
                }
            });

    HttpResponse<JsonNode> response = future.get(); // NOTE: This call is blocking until the request is finished
    if (response != null && response.getStatus() == 200) {
        JsonNode body = response.getBody();
        // TODO Parse body and add items to `stocks`
    }
    return stocks;
}

This method can be used like this:

ArrayList<Stock> stocks = getAllAvailableStocks(...);
stocks.forEach(x -> System.out.println(x));

Edit

If you want to handle the result asynchronously without providing callbacks, you could use a CompletableFuture. Consider the following snippet as a starting point which does not handle unsuccessful calls.

private static CompletableFuture<ArrayList<Stock>> getAllAvailableStocks(String url) {
    CompletableFuture<ArrayList<Stock>> result = new CompletableFuture<>();
    Future<HttpResponse<JsonNode>> future = Unirest.get(url)
              .header("accept", "application/json")
              .asJsonAsync(new Callback<JsonNode>() {
                public void failed(UnirestException e) {
                    System.out.println("The request has failed");
                }

                public void completed(HttpResponse<JsonNode> response) {
                    System.out.println("The request succeeded");
                    ArrayList<Stock> stocks = new ArrayList<Stock>();
                    if (response != null && response.getStatus() == 200) {
                        JsonNode body = response.getBody();
                        // TODO Parse body and add items to `stocks`
                    }
                    result.complete(stocks);
                }

                public void cancelled() {
                    System.out.println("The request has been cancelled");
                }
            });

    return result;
}

The method can be used as follows:

CompletableFuture<ArrayList<Stock>> stocksFuture = getAllAvailableStocks(...);
stocksFuture.thenAccept((stocks) -> {
    // NOTE: This will be called after and only if the request succeeded
    stocks.forEach(x -> System.out.println(x));
});

System.out.println("This is probably executed before the above request finished.");

Thread.sleep(10000); // If you are calling from your `main` method: Prevent JVM exit
trylimits
  • 2,575
  • 1
  • 22
  • 32