Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ final class BufferedOutStream extends OutputStream {
private long count;

BufferedOutStream(JdkContext context, int initial, long max) {

this.context = context;
this.max = max;
this.buffer = new ByteArrayOutputStream(initial);
Expand Down
10 changes: 10 additions & 0 deletions avaje-jex/src/main/java/io/avaje/jex/core/JdkContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,16 @@ public void write(byte[] bytes) {
}
}

@Override
public void write(byte[] bufferBytes, int length) {
try (var os = exchange.getResponseBody()) {
exchange.sendResponseHeaders(statusCode(), length == 0 ? -1 : length);
os.write(bufferBytes, 0, length);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}

@Override
public void write(InputStream is) {
try (is; var os = outputStream()) {
Expand Down
64 changes: 64 additions & 0 deletions avaje-jex/src/main/java/io/avaje/jex/core/json/JsonbOutput.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package io.avaje.jex.core.json;

import io.avaje.jex.http.Context;
import io.avaje.json.stream.JsonOutput;

import java.io.IOException;
import java.io.OutputStream;

/**
* avaje-jsonb output that allows for writing fixed length content
* straight from the avaje-jsonb buffer, avoiding the jex side buffer.
*/
public final class JsonbOutput implements JsonOutput {

private final Context context;
private OutputStream os;

public static JsonOutput of(Context context) {
return new JsonbOutput(context);
}

private JsonbOutput(Context context) {
this.context = context;
}

@Override
public void write(byte[] content, int offset, int length) throws IOException {
if (os == null) {
// exceeds the avaje-jsonb buffer size
os = context.outputStream();
}
os.write(content, offset, length);
}

@Override
public void writeLast(byte[] content, int offset, int length) throws IOException {
if (os == null) {
// write as fixed length content straight from the avaje-jsonb buffer
context.write(content, length);
} else {
os.write(content, offset, length);
}
}

@Override
public void flush() throws IOException {
if (os != null) {
os.flush();
}
}

@Override
public void close() throws IOException {
if (os != null) {
os.close();
}
}

@Override
public OutputStream unwrapOutputStream() {
return context.outputStream();
}

}
10 changes: 10 additions & 0 deletions avaje-jex/src/main/java/io/avaje/jex/http/Context.java
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,16 @@ default String userAgent() {
*/
void write(byte[] bytes);

/**
* Writes the first bytes from this buffer directly to the response.
*
* <p>The bytes written will be from position 0 to length.
*
* @param bufferBytes The byte array to write.
* @param length The number of bytes to write from the buffer.
*/
void write(byte[] bufferBytes, int length);

/**
* Writes the content from the given InputStream directly to the response body.
*
Expand Down
23 changes: 23 additions & 0 deletions avaje-jex/src/test/java/io/avaje/jex/core/JsonTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import java.util.concurrent.locks.LockSupport;
import java.util.stream.Stream;

import io.avaje.jex.core.json.JsonbOutput;
import io.avaje.jsonb.Json;
import io.avaje.jsonb.JsonType;
import io.avaje.jsonb.Jsonb;
Expand Down Expand Up @@ -58,6 +59,13 @@ static TestPair init() {
var result = HelloDto.rob();
jsonTypeHelloDto.toJson(result, ctx.outputStream());
})
.get(
"/usingJsonOutput",
ctx -> {
ctx.status(200).contentType("application/json");
var result = HelloDto.fi();
jsonTypeHelloDto.toJson(result, JsonbOutput.of(ctx));
})
.get("/iterate", ctx -> ctx.jsonStream(ITERATOR))
.get("/stream", ctx -> ctx.jsonStream(HELLO_BEANS.stream()))
.post("/", ctx -> ctx.text("bean[" + ctx.bodyAsClass(HelloDto.class) + "]"));
Expand Down Expand Up @@ -118,6 +126,21 @@ void usingOutputStream() {
assertThat(bean.name).isEqualTo("rob");
}

@Test
void usingJsonOutput() {
var hres = pair.request().path("usingJsonOutput")
.GET()
.as(HelloDto.class);

assertThat(hres.statusCode()).isEqualTo(200);
final HttpHeaders headers = hres.headers();
assertThat(headers.firstValue("Content-Type").orElseThrow()).isEqualTo("application/json");

var bean = hres.body();
assertThat(bean.id).isEqualTo(45);
assertThat(bean.name).isEqualTo("fi");
}


@Test
void stream_viaIterator() {
Expand Down