2

The legacy java http client provided an OutputStream using URLConnection.getOutputStream. Writing a json body for example worked like the following:

final URLConnection urlConnection = ...;
try (OutputStreamWriter writer = new OutputStreamWriter(urlConnection.getOutputStream())) {
    new Gson().toJson(someJsonObject, writer);
}

What's the equivalent way of stream-writing a request body with the new java 11 http client?

The only alternative I found is to write the entire output into a String or byte[] and use BodyPublishers.ofString/ofByteArray, however this seems rather inefficient to me for larger requests.

Florian
  • 23
  • 1
  • 5
  • 2
    https://docs.oracle.com/en/java/javase/11/docs/api/java.net.http/java/net/http/HttpRequest.BodyPublishers.html#ofInputStream(java.util.function.Supplier). The problem you’re seeing that the J11 client is _reactive_ - i.e. the client will request “more data” and you send it via the `Flow` api; a `BodyPublisher` is actually just a `Flow`. Gson, on the other hand, is based on old pull based, blocking, APIs. You’ll need to either 1) use a JSON serialiser that supports reactive or 2) use `PipelineInputStream` to essentially allow the `Flow` API to block the producing thread - not ideal – Boris the Spider Apr 27 '21 at 06:40

1 Answers1

0

You can use Methanol's WritableBodyPublisher. It allows you to stream the request body through an OutputStream or a WritableByteChannel. The publisher buffers the body in memory as you're writing it. If you want it to get sent while writing you'll need to either use sendAsync beforehand or do the writing in another thread. This is somewhat similar to URLConnection's behavior.

var publisher = WritableBodyPublisher.create();
var request = HttpRequest.newBuilder()
    .uri(URI.create("https://example.com"))
    .POST(publisher)
    .build();
var responseAsync = client.sendAsync(request, BodyHandlers.ofString());

try (var writer = new OutputStreamWriter(publisher.outputStream())) {
  new Gson().toJson(someJsonObject, writer);
}