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>
.