Home > database >  WebClient exchangeToMono retrieving empty body
WebClient exchangeToMono retrieving empty body

Time:12-22

When using WebClient's exchangeToMono() the body retrieving part is always returning an empty Mono:

Example, the exposed service which returns a non-empty Mono

@PostMapping("/test")
public Mono<Pojo> getCalled(@RequestBody Pojo pojo) {
    System.out.println(pojo); // always prints a non-null object
    return Mono.just(pojo);
}

WebClient with .retrieve()

WebClient.create().post().uri(theUrl).bodyValue(p).retrieve().toEntity(Pojo.class).map(response -> {
    if (response.getStatusCode().isError()) {
        // do something;
    }
    return response.getBody();
}).single(); // always get a single element and does not fail

WebClient with .exchangeToMono()

WebClient.create().post().uri(theUrl).bodyValue(p).exchangeToMono(Mono::just).flatMap(response -> {
    if (response.statusCode().isError()) {
        // do something;
    }

    return response.bodyToMono(Pojo.class).single(); // fails with java.util.NoSuchElementException: Source was empty
});

Am I doing something wrong?

CodePudding user response:

The response Mono is empty because it has already been consumed by .exchangeToMono, thus single() operator fails with NoSuchElementException as expected.

CodePudding user response:

i have no idea why you are doing exchangeToMono(Mono::just).flatMap(response -> ...) as it makes no sense.

No you don't need to consume the Mono twice, what you need is to read the documentation on how to use the exchange function properly WebClient > Exchange

Here is the example taken from the docs

Mono<Person> entityMono = client.get()
        .uri("/persons/1")
        .accept(MediaType.APPLICATION_JSON)
        .exchangeToMono(response -> {
            if (response.statusCode().equals(HttpStatus.OK)) {
                return response.bodyToMono(Person.class);
            }
            else {
                // Turn to error
                return response.createException().flatMap(Mono::error);
            }
        });

And here is your code, but doing the things in the exchangeToMono instead

WebClient.create().post().uri(theUrl).bodyValue(p).exchangeToMono(response -> {
    if (response.statusCode().isError()) {
        // do something;
    }

    return response.bodyToMono(Pojo.class).single();
});

exchangeToMono has a purpose, its not there to just put stuff into a Mono<T> its there because you need to consume the response so that the server can release the connection that has been allocated. You do that by doing your checks etc in the exchangeToMono and then extract the body to a Mono<T>.

  • Related