From 9feb173c5aa3640c5e5db9b470a393d0413f2b28 Mon Sep 17 00:00:00 2001
From: Georgios Andrianakis <geoand@gmail.com>
Date: Wed, 15 May 2024 12:03:54 +0300
Subject: [PATCH] Fix List form handling in REST Client bean params

Fixes: #40324
---
 .../JaxrsClientReactiveProcessor.java         | 11 +++++-----
 .../rest/client/reactive/FormListTest.java    | 20 +++++++++++++------
 .../processor/beanparam/BeanParamParser.java  |  8 ++++----
 .../processor/beanparam/FormParamItem.java    |  8 +++++---
 4 files changed, 29 insertions(+), 18 deletions(-)

diff --git a/extensions/resteasy-reactive/rest-client-jaxrs/deployment/src/main/java/io/quarkus/jaxrs/client/reactive/deployment/JaxrsClientReactiveProcessor.java b/extensions/resteasy-reactive/rest-client-jaxrs/deployment/src/main/java/io/quarkus/jaxrs/client/reactive/deployment/JaxrsClientReactiveProcessor.java
index 9529ffff88426..73c7537d32921 100644
--- a/extensions/resteasy-reactive/rest-client-jaxrs/deployment/src/main/java/io/quarkus/jaxrs/client/reactive/deployment/JaxrsClientReactiveProcessor.java
+++ b/extensions/resteasy-reactive/rest-client-jaxrs/deployment/src/main/java/io/quarkus/jaxrs/client/reactive/deployment/JaxrsClientReactiveProcessor.java
@@ -1030,7 +1030,7 @@ A more full example of generated client (with sub-resource) can is at the bottom
                             // NOTE: don't use type here, because we're not going through the collection converters and stuff
                             Type parameterType = jandexMethod.parameterType(paramIdx);
                             addFormParam(methodCreator, param.name, methodCreator.getMethodParam(paramIdx),
-                                    parameterType, param.declaredType, param.signature, index,
+                                    parameterType, param.signature, index,
                                     restClientInterface.getClassName(), methodCreator.getThis(), formParams,
                                     getGenericTypeFromArray(methodCreator, methodGenericParametersField, paramIdx),
                                     getAnnotationsFromArray(methodCreator, methodParamAnnotationsField, paramIdx),
@@ -2538,7 +2538,7 @@ private void addSubBeanParamData(MethodInfo jandexMethod, int paramIndex, Byteco
                 case FORM_PARAM:
                     FormParamItem formParam = (FormParamItem) item;
                     addFormParam(creator, formParam.getFormParamName(), formParam.extract(creator, param),
-                            jandexMethod.parameterType(paramIndex), formParam.getParamType(), formParam.getParamSignature(),
+                            formParam.getParamType(), formParam.getParamSignature(),
                             index,
                             restClientInterfaceClassName, client,
                             formParams,
@@ -2810,7 +2810,6 @@ private void addFormParam(BytecodeCreator methodCreator,
             String paramName,
             ResultHandle formParamHandle,
             Type parameterType,
-            String parameterTypeStr,
             String parameterSignature,
             IndexView index,
             String restClientInterfaceClassName, ResultHandle client, AssignableResultHandle formParams,
@@ -2818,7 +2817,8 @@ private void addFormParam(BytecodeCreator methodCreator,
             ResultHandle parameterAnnotations, boolean multipart,
             String partType, String partFilename, String errorLocation) {
         if (multipart) {
-            handleMultipartField(paramName, partType, partFilename, parameterTypeStr, parameterSignature, formParamHandle,
+            handleMultipartField(paramName, partType, partFilename, parameterType.name().toString(), parameterSignature,
+                    formParamHandle,
                     formParams, methodCreator,
                     client, restClientInterfaceClassName, parameterAnnotations, genericType,
                     errorLocation);
@@ -2846,7 +2846,8 @@ private void addFormParam(BytecodeCreator methodCreator,
                 creator.invokeInterfaceMethod(MULTIVALUED_MAP_ADD_ALL, formParams,
                         creator.load(paramName), convertedParamArray);
             } else {
-                ResultHandle convertedFormParam = convertParamToString(creator, client, formParamHandle, parameterTypeStr,
+                ResultHandle convertedFormParam = convertParamToString(creator, client, formParamHandle,
+                        parameterType.name().toString(),
                         genericType, parameterAnnotations);
                 BytecodeCreator parameterIsStringBranch = checkStringParam(creator, convertedFormParam,
                         restClientInterfaceClassName, errorLocation);
diff --git a/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/FormListTest.java b/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/FormListTest.java
index b05f4c58b8031..fe0bfd9543c30 100644
--- a/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/FormListTest.java
+++ b/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/FormListTest.java
@@ -5,6 +5,7 @@
 import java.net.URI;
 import java.util.List;
 
+import jakarta.ws.rs.BeanParam;
 import jakarta.ws.rs.POST;
 import jakarta.ws.rs.Path;
 
@@ -26,19 +27,21 @@ public class FormListTest {
     URI baseUri;
 
     @Test
-    void testHeadersWithSubresource() {
+    void test() {
         Client client = RestClientBuilder.newBuilder().baseUri(baseUri).build(Client.class);
 
-        assertThat(client.call(List.of("first", "second", "third"))).isEqualTo("first-second-third");
-        assertThat(client.call(List.of("first"))).isEqualTo("first");
+        Holder holder = new Holder();
+        holder.input2 = List.of("1", "2");
+        assertThat(client.call(List.of("first", "second", "third"), holder)).isEqualTo("first-second-third/1-2");
+        assertThat(client.call(List.of("first"), holder)).isEqualTo("first/1-2");
     }
 
     @Path("/test")
     public static class Resource {
 
         @POST
-        public String response(@RestForm List<String> input) {
-            return String.join("-", input);
+        public String response(@RestForm List<String> input, @RestForm List<String> input2) {
+            return String.join("-", input) + "/" + String.join("-", input2);
         }
     }
 
@@ -46,6 +49,11 @@ public String response(@RestForm List<String> input) {
     public interface Client {
 
         @POST
-        String call(@RestForm List<String> input);
+        String call(@RestForm List<String> input, @BeanParam Holder holder);
+    }
+
+    public static class Holder {
+        @RestForm
+        public List<String> input2;
     }
 }
diff --git a/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/BeanParamParser.java b/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/BeanParamParser.java
index fa2a9595cf73c..d16c9d11eb1c4 100644
--- a/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/BeanParamParser.java
+++ b/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/BeanParamParser.java
@@ -162,12 +162,12 @@ private static List<Item> parseInternal(ClassInfo beanParamClass, IndexView inde
 
             resultList.addAll(paramItemsForFieldsAndMethods(beanParamClass, FORM_PARAM,
                     (annotationValue, fieldInfo) -> new FormParamItem(fieldInfo.name(), annotationValue,
-                            fieldInfo.type().name().toString(), AsmUtil.getSignature(fieldInfo.type()),
+                            fieldInfo.type(), AsmUtil.getSignature(fieldInfo.type()),
                             fieldInfo.name(),
                             partType(fieldInfo), fileName(fieldInfo), fieldInfo.hasDeclaredAnnotation(ENCODED),
                             new FieldExtractor(null, fieldInfo.name(), fieldInfo.declaringClass().name().toString())),
                     (annotationValue, getterMethod) -> new FormParamItem(getterMethod.name(), annotationValue,
-                            getterMethod.returnType().name().toString(),
+                            getterMethod.returnType(),
                             AsmUtil.getSignature(getterMethod.returnType()),
                             getterMethod.name(),
                             partType(getterMethod), fileName(getterMethod), getterMethod.hasDeclaredAnnotation(ENCODED),
@@ -176,13 +176,13 @@ private static List<Item> parseInternal(ClassInfo beanParamClass, IndexView inde
             resultList.addAll(paramItemsForFieldsAndMethods(beanParamClass, REST_FORM_PARAM,
                     (annotationValue, fieldInfo) -> new FormParamItem(fieldInfo.name(),
                             annotationValue != null ? annotationValue : fieldInfo.name(),
-                            fieldInfo.type().name().toString(), AsmUtil.getSignature(fieldInfo.type()),
+                            fieldInfo.type(), AsmUtil.getSignature(fieldInfo.type()),
                             fieldInfo.name(),
                             partType(fieldInfo), fileName(fieldInfo), fieldInfo.hasDeclaredAnnotation(ENCODED),
                             new FieldExtractor(null, fieldInfo.name(), fieldInfo.declaringClass().name().toString())),
                     (annotationValue, getterMethod) -> new FormParamItem(getterMethod.name(),
                             annotationValue != null ? annotationValue : getterName(getterMethod),
-                            getterMethod.returnType().name().toString(),
+                            getterMethod.returnType(),
                             AsmUtil.getSignature(getterMethod.returnType()),
                             getterMethod.name(),
                             partType(getterMethod), fileName(getterMethod), getterMethod.hasDeclaredAnnotation(ENCODED),
diff --git a/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/FormParamItem.java b/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/FormParamItem.java
index 2fada96647f7c..70f7007ccffd1 100644
--- a/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/FormParamItem.java
+++ b/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/FormParamItem.java
@@ -1,15 +1,17 @@
 package org.jboss.resteasy.reactive.client.processor.beanparam;
 
+import org.jboss.jandex.Type;
+
 public class FormParamItem extends Item {
 
     private final String formParamName;
-    private final String paramType;
+    private final Type paramType;
     private final String paramSignature;
     private final String mimeType;
     private final String fileName;
     private final String sourceName;
 
-    public FormParamItem(String fieldName, String formParamName, String paramType, String paramSignature,
+    public FormParamItem(String fieldName, String formParamName, Type paramType, String paramSignature,
             String sourceName,
             String mimeType, String fileName,
             boolean encoded,
@@ -27,7 +29,7 @@ public String getFormParamName() {
         return formParamName;
     }
 
-    public String getParamType() {
+    public Type getParamType() {
         return paramType;
     }