is there a good way to generate curl
from java.net.http.HttpRequest
? It seems like there is no good way to get the body (if there is a body), the closest thing to it is bodyPublisher()
that returns Optional<BodyPublisher>
that has only long contentLength()
method.
Indeed, it's way trickier than it looks like.
The HttpRequest
of java.net.http
package is a generic object that can be used as request for any type of HttpClient<?>
, hence it doesn't know what the body is, and generically provides a body publisher (type unknown) to which subscribers of a specific type can subscribe in a custom way in order to get the content from it.
This is very different from HttpResponse<?>
, that you usually get from a HttpClient<?>
with a specific type (usually String
) and that can so trivially return you a String getBody()
.
If you don't want to use any third-party library (which already implement the below logic), this is the way you can extract the (String
) body from the publisher:
String requestBody = httpRequest.bodyPublisher().map(p -> {
HttpResponse.BodySubscriber<String> bodySubscriber = HttpResponse.BodySubscribers.ofString(StandardCharsets.UTF_8);
StringSubscriber stringSubscriber = new StringSubscriber(bodySubscriber);
p.subscribe(stringSubscriber);
return bodySubscriber.getBody().toCompletableFuture().join();
}).orElse("");
... where httpRequest
is your java.net.http.HttpRequest
and StringSubscriber
is an implementation of Flow.Subscriber<ByteBuffer>
like follows:
class StringSubscriber implements Flow.Subscriber<ByteBuffer> {
private final HttpResponse.BodySubscriber<String> wrapped;
private StringSubscriber(HttpResponse.BodySubscriber<String> wrapped) {
this.wrapped = wrapped;
}
@Override
public void onSubscribe(Flow.Subscription subscription) {
wrapped.onSubscribe(subscription);
}
@Override
public void onNext(ByteBuffer item) {
wrapped.onNext(List.of(item));
}
@Override
public void onError(Throwable throwable) {
wrapped.onError(throwable);
}
@Override
public void onComplete() {
wrapped.onComplete();
}
}
Explanation:
If there is no BodyPublisher
in your request, you simply return an empty string (assuming that means no body, you can customize it to null
or whatever you want).
Else, if there is a BodyPublisher
in your request, then you will do the following:
BodySubscriber
of type String
(meaning you will subscribe to a publisher that can provide a String
version of its body)StringSubscriber
(your own implementation that I posted above).join()
it)