Repository: quarkusio/quarkus
Issue: Quarkus Multipart not working for multi layer applications

### Describe the bug

We have an export-import microservice design that exports and imports data, one microservice component per family of entities.
This microservice design imports & exports using rest reactive design. And it works perfectly without any issues. 

**Requirement**
But now we have a different requirement. We have a module that provides the user a page to select the list of microservices that needs to be exported and/or imported. After selecting multiple microservices and clicking on "Export" button, a zip file will be generated that contains the exported file of all the microservices selected on the page.

**Design**
Since all the components already have the export import function, all I have to do is created a separate service that will do the following.
- Take a request that comprises the selected component names.
- Iterate through the component names, and build a Unijoin list to call the export import function of all the microservices in parallel.
`UniJoin.Builder<CommonAccountTypeXMLDto> builder = Uni.join().builder();
builder.joinAll().andFailFast();`
- Collect the files into a zip file, and return the zip file.

**Issue**
The service uses Rest Reactive Client to connect to the individual microservices. So I use the 'Rest Reactive Client with Multipart' approach. But it gives an error.
`022-02-25 16:13:11,174 ERROR [org.jbo.res.rea.com.cor.AbstractResteasyReactiveContext] (executor-thread-0) Request failed: javax.ws.rs.ProcessingException: Response could not be mapped to type class com.company.services.exim.client.DownloadFormData`

### Expected behavior

A Quarkus microservice using Rest Reactive Client fails with an exception when it connects with a Quarkus Rest Reactive Service. Though the requirement is for Multipart bodies, it fails for normal bodies too.

In summary, a Quarkus service calling another quarkus service using Rest Reactive Client fails.

### Actual behavior

Quarkus Rest Reactive Client should be able to connect to a Quarkus Rest Service.

### How to Reproduce?

Steps to reproduce the issue:

1. Create a Restful Reactive service with two methods, one returning a normal class, while other returns Multipart.
2. Create a separate service with a Restful Reactive Client having the same two methods as defined in Step 1.
3. Call the service through postman.

Error occurs:
`022-02-25 16:13:11,174 ERROR [org.jbo.res.rea.com.cor.AbstractResteasyReactiveContext] (executor-thread-0) Request failed: javax.ws.rs.ProcessingException: **** could not be mapped to type class ***.***.***.*******`


### Output of `uname -a` or `ver`

Microsoft Windows [Version 10.0.19044.1526]

### Output of `java -version`

Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.11+9-LTS-194, mixed mode)

### GraalVM version (if different from Java)

_No response_

### Quarkus version or git rev

2.5.0.FINAL

### Build tool (ie. output of `mvnw --version` or `gradlew --version`)

Apache Maven 3.8.3 (ff8e977a158738155dc465c6a97ffaf31982d739)

### Additional information

[Error.txt](https://github.com/quarkusio/quarkus/files/8145574/Error.txt)
[raj-quarkus-multipart.zip](https://github.com/quarkusio/quarkus/files/8145575/raj-quarkus-multipart.zip)

**Sample**
For the sake of simplicity, I am attaching a single project that contains a server project and a client project.
- Server package returns a multipart object when export is clicked.
- Client package contains the Rest Reactive Client to call the server project.

Also attached is the error text. You can run the project and reproduce the same error. Use postman to call the function.

Please help find the actual cause of the error. Thanks!

Changed files:
extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/multipart/MultipartResponseTest.java
independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/multipart/QuarkusMultipartFormUpload.java
independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/multipart/QuarkusMultipartResponseDataFactory.java

diff --git a/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/multipart/MultipartResponseTest.java b/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/multipart/MultipartResponseTest.java
index 4c73daa59c3..ab9c432c4f4 100644
--- a/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/multipart/MultipartResponseTest.java
+++ b/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/multipart/MultipartResponseTest.java
@@ -43,7 +43,7 @@ void shouldParseMultipartResponse() {
         Client client = RestClientBuilder.newBuilder().baseUri(baseUri).build(Client.class);
         MultipartData data = client.getFile();
         assertThat(data.file).exists();
-        verifyWooHooFile(data.file);
+        verifyWooHooFile(data.file, 10000);
         assertThat(data.name).isEqualTo("foo");
         assertThat(data.panda.weight).isEqualTo("huge");
         assertThat(data.panda.height).isEqualTo("medium");
@@ -52,6 +52,18 @@ void shouldParseMultipartResponse() {
         assertThat(data.numberz).containsSequence(2008, 2011, 2014);
     }
 
+    @Test
+    void shouldParseMultipartResponseWithSmallFile() {
+        Client client = RestClientBuilder.newBuilder().baseUri(baseUri).build(Client.class);
+        MultipartData data = client.getSmallFile();
+        assertThat(data.file).exists();
+        verifyWooHooFile(data.file, 1);
+        assertThat(data.name).isEqualTo("foo");
+        assertThat(data.panda).isNull();
+        assertThat(data.number).isEqualTo(1984);
+        assertThat(data.numberz).isNull();
+    }
+
     @Test
     void shouldParseMultipartResponseWithNulls() {
         Client client = RestClientBuilder.newBuilder().baseUri(baseUri).build(Client.class);
@@ -93,7 +105,7 @@ void shouldParseMultipartResponseWithClientBuilderApi() {
         assertThat(data.numbers).containsSequence(2008, 2011, 2014);
     }
 
-    void verifyWooHooFile(File file) {
+    void verifyWooHooFile(File file, int expectedTimes) {
         int position = 0;
         try (FileReader reader = new FileReader(file)) {
             int read;
@@ -101,7 +113,7 @@ void verifyWooHooFile(File file) {
                 assertThat((char) read).isEqualTo(WOO_HOO_WOO_HOO_HOO.charAt(position % WOO_HOO_WOO_HOO_HOO.length()));
                 position++;
             }
-            assertThat(position).isEqualTo(WOO_HOO_WOO_HOO_HOO.length() * 10000);
+            assertThat(position).isEqualTo(WOO_HOO_WOO_HOO_HOO.length() * expectedTimes);
         } catch (IOException e) {
             fail("failed to read provided file", e);
         }
@@ -113,6 +125,11 @@ public interface Client {
         @Produces(MediaType.MULTIPART_FORM_DATA)
         MultipartData getFile();
 
+        @GET
+        @Produces(MediaType.MULTIPART_FORM_DATA)
+        @Path("/small")
+        MultipartData getSmallFile();
+
         @GET
         @Produces(MediaType.MULTIPART_FORM_DATA)
         @Path("/empty")
@@ -146,6 +163,19 @@ public MultipartData getFile() throws IOException {
                     1984, new int[] { 2008, 2011, 2014 });
         }
 
+        @GET
+        @Produces(MediaType.MULTIPART_FORM_DATA)
+        @Path("/small")
+        public MultipartData getSmallFile() throws IOException {
+            File file = File.createTempFile("toDownload", ".txt");
+            file.deleteOnExit();
+            // let's write Woo hoo, woo hoo hoo 1 time
+            try (FileOutputStream out = new FileOutputStream(file)) {
+                out.write(WOO_HOO_WOO_HOO_HOO.getBytes(StandardCharsets.UTF_8));
+            }
+            return new MultipartData("foo", file, null, 1984, null);
+        }
+
         @GET
         @Produces(MediaType.MULTIPART_FORM_DATA)
         @Path("/empty")
diff --git a/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/multipart/QuarkusMultipartFormUpload.java b/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/multipart/QuarkusMultipartFormUpload.java
index 14af23304ae..c784f803436 100644
--- a/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/multipart/QuarkusMultipartFormUpload.java
+++ b/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/multipart/QuarkusMultipartFormUpload.java
@@ -51,7 +51,7 @@ public QuarkusMultipartFormUpload(Context context,
                 io.netty.handler.codec.http.HttpMethod.POST,
                 "/");
         Charset charset = parts.getCharset() != null ? parts.getCharset() : HttpConstants.DEFAULT_CHARSET;
-        DefaultHttpDataFactory httpDataFactory = new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE, charset) {
+        DefaultHttpDataFactory httpDataFactory = new DefaultHttpDataFactory(-1, charset) {
             @Override
             public FileUpload createFileUpload(HttpRequest request, String name, String filename, String contentType,
                     String contentTransferEncoding, Charset _charset, long size) {
diff --git a/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/multipart/QuarkusMultipartResponseDataFactory.java b/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/multipart/QuarkusMultipartResponseDataFactory.java
index 0770f91f9e9..72758422c29 100644
--- a/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/multipart/QuarkusMultipartResponseDataFactory.java
+++ b/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/multipart/QuarkusMultipartResponseDataFactory.java
@@ -25,9 +25,7 @@
 import io.netty.handler.codec.http.multipart.HttpData;
 import io.netty.handler.codec.http.multipart.InterfaceHttpData;
 import io.netty.handler.codec.http.multipart.MemoryAttribute;
-import io.netty.handler.codec.http.multipart.MemoryFileUpload;
 import io.netty.handler.codec.http.multipart.MixedAttribute;
-import io.netty.handler.codec.http.multipart.MixedFileUpload;
 import io.vertx.core.http.HttpClientResponse;
 import java.io.IOException;
 import java.nio.charset.Charset;
@@ -240,31 +238,16 @@ public Attribute createAttribute(HttpClientResponse response, String name, Strin
     }
 
     // to reuse netty stuff as much as possible, we use FileUpload class to represent the downloaded file
+    // the difference between this and the original is that we always use DiskFileUpload
     public FileUpload createFileUpload(HttpClientResponse response, String name, String filename,
             String contentType, String contentTransferEncoding, Charset charset,
             long size) {
-        if (useDisk) {
-            FileUpload fileUpload = new DiskFileUpload(name, filename, contentType,
-                    contentTransferEncoding, charset, size, baseDir, deleteOnExit);
-            fileUpload.setMaxSize(maxSize);
-            checkHttpDataSize(fileUpload);
-            List<HttpData> list = getList(response);
-            list.add(fileUpload);
-            return fileUpload;
-        }
-        if (checkSize) {
-            FileUpload fileUpload = new MixedFileUpload(name, filename, contentType,
-                    contentTransferEncoding, charset, size, minSize, baseDir, deleteOnExit);
-            fileUpload.setMaxSize(maxSize);
-            checkHttpDataSize(fileUpload);
-            List<HttpData> list = getList(response);
-            list.add(fileUpload);
-            return fileUpload;
-        }
-        MemoryFileUpload fileUpload = new MemoryFileUpload(name, filename, contentType,
-                contentTransferEncoding, charset, size);
+        FileUpload fileUpload = new DiskFileUpload(name, filename, contentType,
+                contentTransferEncoding, charset, size, baseDir, deleteOnExit);
         fileUpload.setMaxSize(maxSize);
         checkHttpDataSize(fileUpload);
+        List<HttpData> list = getList(response);
+        list.add(fileUpload);
         return fileUpload;
     }