From f4ff81d173d9edac67c9d7a38bef0718f4dbb024 Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Tue, 26 Jul 2022 10:55:27 +0300 Subject: [PATCH] Ensure that returning an InputStream from RESTEasy Reactive works in native Fixes: #26780 --- .../InputStreamMessageBodyHandler.java | 4 ++ .../ServerInputStreamMessageBodyHandler.java | 14 ++++- .../client/multipart/MultipartResource.java | 57 +++++++++---------- .../multipart/MultipartResourceTest.java | 9 +++ 4 files changed, 54 insertions(+), 30 deletions(-) diff --git a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/providers/serialisers/InputStreamMessageBodyHandler.java b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/providers/serialisers/InputStreamMessageBodyHandler.java index aba7b355d230a..b5eb4010aadc2 100644 --- a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/providers/serialisers/InputStreamMessageBodyHandler.java +++ b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/providers/serialisers/InputStreamMessageBodyHandler.java @@ -29,6 +29,10 @@ public boolean isWriteable(Class type, Type genericType, Annotation[] annotat @Override public void writeTo(InputStream inputStream, Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException { + writeTo(inputStream, entityStream); + } + + protected void writeTo(InputStream inputStream, OutputStream entityStream) throws IOException { try { byte[] buffer = new byte[8192]; int c; diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerInputStreamMessageBodyHandler.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerInputStreamMessageBodyHandler.java index c643e6d16f675..6424d3fce6c83 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerInputStreamMessageBodyHandler.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/providers/serialisers/ServerInputStreamMessageBodyHandler.java @@ -10,11 +10,12 @@ import org.jboss.resteasy.reactive.common.providers.serialisers.InputStreamMessageBodyHandler; import org.jboss.resteasy.reactive.server.spi.ResteasyReactiveResourceInfo; import org.jboss.resteasy.reactive.server.spi.ServerMessageBodyReader; +import org.jboss.resteasy.reactive.server.spi.ServerMessageBodyWriter; import org.jboss.resteasy.reactive.server.spi.ServerRequestContext; @Provider public class ServerInputStreamMessageBodyHandler extends InputStreamMessageBodyHandler - implements ServerMessageBodyReader { + implements ServerMessageBodyReader, ServerMessageBodyWriter { @Override public boolean isReadable(Class type, Type genericType, ResteasyReactiveResourceInfo lazyMethod, MediaType mediaType) { @@ -33,4 +34,15 @@ public long getSize(InputStream inputStream, Class type, Type genericType, An return -1; } + @Override + public boolean isWriteable(Class type, Type genericType, ResteasyReactiveResourceInfo target, + MediaType mediaType) { + return super.isWriteable(type, null, null, null); + } + + @Override + public void writeResponse(InputStream is, Type genericType, ServerRequestContext context) + throws WebApplicationException, IOException { + writeTo(is, context.getOrCreateOutputStream()); + } } diff --git a/integration-tests/rest-client-reactive-multipart/src/main/java/io/quarkus/it/rest/client/multipart/MultipartResource.java b/integration-tests/rest-client-reactive-multipart/src/main/java/io/quarkus/it/rest/client/multipart/MultipartResource.java index a24fb95c3cc98..5006915153eae 100644 --- a/integration-tests/rest-client-reactive-multipart/src/main/java/io/quarkus/it/rest/client/multipart/MultipartResource.java +++ b/integration-tests/rest-client-reactive-multipart/src/main/java/io/quarkus/it/rest/client/multipart/MultipartResource.java @@ -3,8 +3,10 @@ import static java.nio.charset.StandardCharsets.UTF_8; import java.io.File; +import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; import java.nio.file.Files; import java.util.ArrayList; import java.util.List; @@ -25,6 +27,7 @@ import org.jboss.resteasy.reactive.MultipartForm; import org.jboss.resteasy.reactive.PartType; import org.jboss.resteasy.reactive.RestQuery; +import org.jboss.resteasy.reactive.RestResponse; import io.quarkus.it.rest.client.multipart.MultipartClient.FileWithPojo; import io.quarkus.it.rest.client.multipart.MultipartClient.Pojo; @@ -141,12 +144,7 @@ public String sendFileAsBinary(@QueryParam("nullFile") @DefaultValue("false") bo WithFileAsBinaryFile data = new WithFileAsBinaryFile(); if (!nullFile) { - File tempFile = File.createTempFile("quarkus-test", ".bin"); - tempFile.deleteOnExit(); - - try (FileOutputStream fileOutputStream = new FileOutputStream(tempFile)) { - fileOutputStream.write(HELLO_WORLD.getBytes()); - } + File tempFile = createTempHelloWorldFile(); data.file = tempFile; } @@ -163,12 +161,7 @@ public String sendPathAsBinary(@QueryParam("nullFile") @DefaultValue("false") bo WithPathAsBinaryFile data = new WithPathAsBinaryFile(); if (!nullFile) { - File tempFile = File.createTempFile("quarkus-test", ".bin"); - tempFile.deleteOnExit(); - - try (FileOutputStream fileOutputStream = new FileOutputStream(tempFile)) { - fileOutputStream.write(HELLO_WORLD.getBytes()); - } + File tempFile = createTempHelloWorldFile(); data.file = tempFile.toPath(); } @@ -206,12 +199,7 @@ public String sendBufferAsTextFile() { @Produces(MediaType.TEXT_PLAIN) @Blocking public String sendFileAsText() throws IOException { - File tempFile = File.createTempFile("quarkus-test", ".bin"); - tempFile.deleteOnExit(); - - try (FileOutputStream fileOutputStream = new FileOutputStream(tempFile)) { - fileOutputStream.write(HELLO_WORLD.getBytes()); - } + File tempFile = createTempHelloWorldFile(); WithFileAsTextFile data = new WithFileAsTextFile(); data.file = tempFile; @@ -225,12 +213,7 @@ public String sendFileAsText() throws IOException { @Produces(MediaType.TEXT_PLAIN) @Blocking public String sendPathAsText() throws IOException { - File tempFile = File.createTempFile("quarkus-test", ".bin"); - tempFile.deleteOnExit(); - - try (FileOutputStream fileOutputStream = new FileOutputStream(tempFile)) { - fileOutputStream.write(HELLO_WORLD.getBytes()); - } + File tempFile = createTempHelloWorldFile(); WithPathAsTextFile data = new WithPathAsTextFile(); data.file = tempFile.toPath(); @@ -276,17 +259,33 @@ public String consumeBinaryWithPojo(@MultipartForm MultipartBodyWithBinaryFileAn @Path("/produces/multipart") @Produces(MediaType.MULTIPART_FORM_DATA) public MultipartBodyWithTextFile produceMultipart() throws IOException { + File tempFile = createTempHelloWorldFile(); + + MultipartBodyWithTextFile data = new MultipartBodyWithTextFile(); + data.file = tempFile; + data.number = String.valueOf(NUMBER); + return data; + } + + @GET + @Path("/produces/input-stream-rest-response") + public RestResponse produceInputStreamRestResponse() throws IOException { + File tempFile = createTempHelloWorldFile(); + FileInputStream is = new FileInputStream(tempFile); + return RestResponse.ResponseBuilder + .ok(is) + .type(MediaType.TEXT_PLAIN_TYPE) + .build(); + } + + private File createTempHelloWorldFile() throws IOException { File tempFile = File.createTempFile("quarkus-test", ".bin"); tempFile.deleteOnExit(); try (FileOutputStream fileOutputStream = new FileOutputStream(tempFile)) { fileOutputStream.write(HELLO_WORLD.getBytes()); } - - MultipartBodyWithTextFile data = new MultipartBodyWithTextFile(); - data.file = tempFile; - data.number = String.valueOf(NUMBER); - return data; + return tempFile; } private boolean containsHelloWorld(File file) { diff --git a/integration-tests/rest-client-reactive-multipart/src/test/java/io/quarkus/it/rest/client/multipart/MultipartResourceTest.java b/integration-tests/rest-client-reactive-multipart/src/test/java/io/quarkus/it/rest/client/multipart/MultipartResourceTest.java index 8c8d995b56b08..da4fcb1882f54 100644 --- a/integration-tests/rest-client-reactive-multipart/src/test/java/io/quarkus/it/rest/client/multipart/MultipartResourceTest.java +++ b/integration-tests/rest-client-reactive-multipart/src/test/java/io/quarkus/it/rest/client/multipart/MultipartResourceTest.java @@ -229,6 +229,15 @@ public void shouldProperlyHandleOctetStreamFile() { // @formatter:on } + @Test + public void shouldProducesInputStreamRestResponse() { + RestAssured.get("/produces/input-stream-rest-response") + .then() + .contentType(ContentType.TEXT) + .statusCode(200) + .body(equalTo("HELLO WORLD")); + } + private void assertMultipartResponseContains(String response, String name, String contentType, Object value) { String[] lines = response.split("--"); assertThat(lines).anyMatch(line -> line.contains(String.format(EXPECTED_CONTENT_DISPOSITION_PART, name))