1

I am using Java 17. I am trying to get the response from a message service and create a map object. Then send it to the caller method. I am using java.net.http.

I am willing to use a callback so that I could not use join or get to delay the main thread. But at my callback, the message shown unexpected return value.

My attempts are as below:

    LinkedHashMap<String, Object> retVal = new LinkedHashMap<>();

HttpRequest request = HttpRequest.newBuilder(URI.create(url))
                .header("Content-Type", "application/json")
                .POST(HttpRequest.BodyPublishers.ofString(params))
                .build();               
        
HttpClient.newHttpClient()
                .sendAsync(request, HttpResponse.BodyHandlers.ofString())
                .thenApply(responseBody -> {
                    try {
                        LinkedHashMap<String, Object> responseMap = new ObjectMapper().readValue(responseBody.body(), new TypeReference<>() {});

                        ArrayList<LinkedHashMap<String, String>> resultList = (ArrayList<LinkedHashMap<String, String>>) responseMap.get("result");
                        HashMap<String, String> resultMap = resultList.get(0);
                        retVal.put("status", resultMap.get("status"));
                        retVal.put("message", resultMap.get("message"));
                    } catch (JsonProcessingException e) {
                        retVal.put("status", "FAILED");
                        retVal.put("message", e.getMessage());
                        e.printStackTrace();
                    }
                    return retVal;
                })
                .exceptionally(ex -> {
                    retVal.put("status", "FAILED");
                    retVal.put("message", ex.getMessage());
                    System.out.println("Exception occurred: " + ex.getMessage());
                    return retVal;
                })
                .thenAccept(callback);  
                
// Define a callback function
        Consumer<LinkedHashMap<String, Object>> callback = responseBody -> {
            // Send the response back to the caller here
            return responseBody;
        };  

How can I achieve this?

halfer
  • 19,824
  • 17
  • 99
  • 186
Sumon Bappi
  • 1,937
  • 8
  • 38
  • 82
  • 1. if you want to return something then instead of `thenAccept()` use `thenApply()`. If you use `thenAccept()` the only possible value that you can return is `null` - which is the only value compatible with `Void`. 2. in your first lambda, where the parameter is an `HttpResponse`, you should probably look at the HTTP status code before mapping the body to JSon. – daniel Mar 07 '23 at 17:51
  • This looks like a good question, but prior to my edit it rather sounded like a request for free work. It is worth being aware that Stack Overflow gets hundreds of requests for volunteer labour every day, and most of those are downvoted and/or closed (quite rightly). I recommend differentiating your own questions from those - make it clear that you know the work is yours to complete. – halfer Mar 07 '23 at 20:01
  • @daniel if I use only thenApply() then I have to use join other wise it shows error. In first lambda not looking for status code because if it fails Then I have to save response into a table as well – Sumon Bappi Mar 12 '23 at 05:13
  • I guess this is your IDE complaining that you ignore the result (not a compiler error). Then just return null. You're ignoring the returned completable feature anyway, so why not use thenAccept() and return null? – daniel Mar 13 '23 at 14:11
  • @daniel, will check that. But I think if I return null in thenAccept() then the caller method will get null as response – Sumon Bappi Mar 14 '23 at 04:29
  • Yes of course. But you're not using the response in the calling code, which is why you got an error when you tried to use thenApply(). – daniel Mar 14 '23 at 15:10
  • 1
    If you don't want to return null, change your code to: CompletableFuture> result = HttpClient.newClient().sendAsync(...).thenApply(...).exceptionally(...).thenApply(body -> callback(body)); where callback(body) is a Function,Map>. – daniel Mar 14 '23 at 15:18

1 Answers1

0

Method:

public CompletableFuture<Void> thenAccept(Consumer<? super T> action)

can only accept a Consumer object. A Consumer object does not return anything, it only consumes an action so it could for instance look like this:

Consumer<LinkedHashMap<String, Object>> callback = System.out::println;

The best would be to use your consumer method and do there whatever you would like to do with the retVal variable. Instead of returning you have to do your logic inside the callback method. For instance:

Consumer<LinkedHashMap<String, Object>> callback = linkedMap -> {
    if (linkedMap != null) {
        linkedMap.keySet().forEach(k -> doSomethingWithEveryKey(k));
    }
};

If you would like to create a fully asynchronous and non-blocking application you can use Spring Webflux, where your method can look like:

@GetMapping("/firstCall")
public Mono<String> getMessage() {
    return this.client.get().uri("/secondCall").accept(MediaType.APPLICATION_JSON)
            .retrieve()
            .bodyToMono(String.class)
            .map(this::mapResponse);
}

private String mapResponse(String input) {
    return "modified response";
}
halfer
  • 19,824
  • 17
  • 99
  • 186
fascynacja
  • 1,625
  • 4
  • 17
  • 35
  • But user is waiting for a response that was it success or not. That's why I need to return – Sumon Bappi Mar 06 '23 at 11:48
  • I can do it by using get() or join() but that will stop the main thread. So performance will be compromised – Sumon Bappi Mar 06 '23 at 11:49
  • So I assume you are making this call from inside your own controller method (which is handling a REST call)? In your current implementation, the "main" thread is not waiting for the result, and will simply continue without wating and will "lose" the result from the http POST call. I think this sort of functionality which you would like to achieve can be done via Spring Webflux. – fascynacja Mar 06 '23 at 12:16
  • If you will post the whole enclosing method I will try to propose you a solution based on spring Webflux – fascynacja Mar 06 '23 at 12:34
  • I will try Webflux later as you suggest – Sumon Bappi Mar 12 '23 at 05:18