Skip to content

Commit

Permalink
Support using List for sending multiple form values in REST Client
Browse files Browse the repository at this point in the history
  • Loading branch information
geoand authored and poldinik committed Apr 29, 2024
1 parent 3854b5c commit 1a55956
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,8 @@ public class JaxrsClientReactiveProcessor {
String.class, Object.class);
private static final MethodDescriptor MULTIVALUED_MAP_ADD = MethodDescriptor.ofMethod(MultivaluedMap.class, "add",
void.class, Object.class, Object.class);
private static final MethodDescriptor MULTIVALUED_MAP_ADD_ALL = MethodDescriptor.ofMethod(MultivaluedMap.class, "addAll",
void.class, Object.class, Object[].class);
private static final MethodDescriptor PATH_GET_FILENAME = MethodDescriptor.ofMethod(Path.class, "getFileName",
Path.class);
private static final MethodDescriptor OBJECT_TO_STRING = MethodDescriptor.ofMethod(Object.class, "toString", String.class);
Expand Down Expand Up @@ -956,7 +958,7 @@ A more full example of generated client (with sub-resource) can is at the bottom
Supplier<FieldDescriptor> beanParamDescriptorsField = classContext
.getLazyBeanParameterDescriptors(beanParam.type);

formParams = addBeanParamData(jandexMethod, methodCreator, handleBeanParamMethod,
formParams = addBeanParamData(jandexMethod, paramIdx, methodCreator, handleBeanParamMethod,
invocationBuilderRef, classContext, beanParam.getItems(),
methodCreator.getMethodParam(paramIdx), methodTarget, index,
restClientInterface.getClassName(),
Expand Down Expand Up @@ -1024,8 +1026,9 @@ A more full example of generated client (with sub-resource) can is at the bottom
} else if (param.parameterType == ParameterType.FORM) {
formParams = createFormDataIfAbsent(methodCreator, formParams, multipart);
// NOTE: don't use type here, because we're not going through the collection converters and stuff
addFormParam(methodCreator, param.name, methodCreator.getMethodParam(paramIdx), param.declaredType,
param.signature,
Type parameterType = jandexMethod.parameterType(paramIdx);
addFormParam(methodCreator, param.name, methodCreator.getMethodParam(paramIdx),
parameterType, param.declaredType, param.signature, index,
restClientInterface.getClassName(), methodCreator.getThis(), formParams,
getGenericTypeFromArray(methodCreator, methodGenericParametersField, paramIdx),
getAnnotationsFromArray(methodCreator, methodParamAnnotationsField, paramIdx),
Expand Down Expand Up @@ -1459,7 +1462,7 @@ private void handleSubResourceMethod(List<JaxrsClientReactiveEnricherBuildItem>
AssignableResultHandle invocationBuilderRef = handleBeanParamMethod
.createVariable(Invocation.Builder.class);
handleBeanParamMethod.assign(invocationBuilderRef, handleBeanParamMethod.getMethodParam(0));
formParams = addBeanParamData(jandexMethod, subMethodCreator, handleBeanParamMethod,
formParams = addBeanParamData(jandexMethod, methodIndex, subMethodCreator, handleBeanParamMethod,
invocationBuilderRef, subContext, beanParam.getItems(),
paramValue, methodTarget, index,
interfaceClass.name().toString(),
Expand Down Expand Up @@ -1586,7 +1589,7 @@ private void handleSubResourceMethod(List<JaxrsClientReactiveEnricherBuildItem>
AssignableResultHandle invocationBuilderRef = handleBeanParamMethod
.createVariable(Invocation.Builder.class);
handleBeanParamMethod.assign(invocationBuilderRef, handleBeanParamMethod.getMethodParam(0));
formParams = addBeanParamData(jandexMethod, subMethodCreator, handleBeanParamMethod,
formParams = addBeanParamData(jandexMethod, methodIndex, subMethodCreator, handleBeanParamMethod,
invocationBuilderRef, subContext, beanParam.getItems(),
subMethodCreator.getMethodParam(paramIdx), methodTarget, index,
interfaceClass.name().toString(),
Expand Down Expand Up @@ -1771,8 +1774,8 @@ private AssignableResultHandle createRestClientField(String name, ClassCreator c
}

private void handleMultipartField(String formParamName, String partType, String partFilename,
String type,
String parameterGenericType, ResultHandle fieldValue, AssignableResultHandle multipartForm,
String type, String parameterSignature,
ResultHandle fieldValue, AssignableResultHandle multipartForm,
BytecodeCreator methodCreator,
ResultHandle client, String restClientInterfaceClassName, ResultHandle parameterAnnotations,
ResultHandle genericType, String errorLocation) {
Expand Down Expand Up @@ -1806,7 +1809,7 @@ private void handleMultipartField(String formParamName, String partType, String
MethodDescriptor.ofMethod(Buffer.class, "buffer", Buffer.class, byte[].class),
fieldValue);
addBuffer(ifValueNotNull, multipartForm, formParamName, partType, partFilename, buffer, errorLocation);
} else if (parameterGenericType.equals(MULTI_BYTE_SIGNATURE)) {
} else if (parameterSignature.equals(MULTI_BYTE_SIGNATURE)) {
addMultiAsFile(ifValueNotNull, multipartForm, formParamName, partType, partFilename, fieldValue, errorLocation);
} else if (partType != null) {
if (partFilename != null) {
Expand Down Expand Up @@ -2407,7 +2410,7 @@ private Optional<MethodInfo> getJavaMethod(ClassInfo interfaceClass, ResourceMet
}

private AssignableResultHandle addBeanParamData(MethodInfo jandexMethod,
BytecodeCreator methodCreator,
int paramIndex, BytecodeCreator methodCreator,
// Invocation.Builder executePut$$enrichInvocationBuilder${noOfBeanParam}(Invocation.Builder)
BytecodeCreator invocationBuilderEnricher,
AssignableResultHandle invocationBuilder,
Expand All @@ -2429,15 +2432,16 @@ private AssignableResultHandle addBeanParamData(MethodInfo jandexMethod,
formParams = createFormDataIfAbsent(methodCreator, formParams, multipart);
}

addSubBeanParamData(jandexMethod, methodCreator, invocationBuilderEnricher, invocationBuilder, classContext,
addSubBeanParamData(jandexMethod, paramIndex, methodCreator, invocationBuilderEnricher, invocationBuilder,
classContext,
beanParamItems, param, target,
index, restClientInterfaceClassName, client, invocationEnricherClient, formParams,
descriptorsField, multipart, beanParamClass);

return formParams;
}

private void addSubBeanParamData(MethodInfo jandexMethod, BytecodeCreator methodCreator,
private void addSubBeanParamData(MethodInfo jandexMethod, int paramIndex, BytecodeCreator methodCreator,
// Invocation.Builder executePut$$enrichInvocationBuilder${noOfBeanParam}(Invocation.Builder)
BytecodeCreator invocationBuilderEnricher,
AssignableResultHandle invocationBuilder,
Expand Down Expand Up @@ -2475,7 +2479,7 @@ private void addSubBeanParamData(MethodInfo jandexMethod, BytecodeCreator method
ResultHandle beanParamElementHandle = beanParamItem.extract(creator, param);
Supplier<FieldDescriptor> newBeanParamDescriptorField = classContext
.getLazyBeanParameterDescriptors(beanParamItem.className());
addSubBeanParamData(jandexMethod, creator, invoEnricher, invocationBuilder, classContext,
addSubBeanParamData(jandexMethod, paramIndex, creator, invoEnricher, invocationBuilder, classContext,
beanParamItem.items(), beanParamElementHandle, target, index, restClientInterfaceClassName, client,
invocationEnricherClient, formParams,
newBeanParamDescriptorField, multipart,
Expand Down Expand Up @@ -2520,7 +2524,9 @@ private void addSubBeanParamData(MethodInfo jandexMethod, BytecodeCreator method
case FORM_PARAM:
FormParamItem formParam = (FormParamItem) item;
addFormParam(creator, formParam.getFormParamName(), formParam.extract(creator, param),
formParam.getParamType(), formParam.getParamSignature(), restClientInterfaceClassName, client,
jandexMethod.parameterType(paramIndex), formParam.getParamType(), formParam.getParamSignature(),
index,
restClientInterfaceClassName, client,
formParams,
getGenericTypeFromParameter(creator, beanParamDescriptorField, item.fieldName()),
getAnnotationsFromParameter(creator, beanParamDescriptorField, item.fieldName()),
Expand Down Expand Up @@ -2786,25 +2792,53 @@ private void addPathParam(BytecodeCreator methodCreator, AssignableResultHandle
methodCreator.load(paramName), handle));
}

private void addFormParam(BytecodeCreator methodCreator, String paramName, ResultHandle formParamHandle,
String parameterType, String parameterGenericType,
private void addFormParam(BytecodeCreator methodCreator,
String paramName,
ResultHandle formParamHandle,
Type parameterType,
String parameterTypeStr,
String parameterSignature,
IndexView index,
String restClientInterfaceClassName, ResultHandle client, AssignableResultHandle formParams,
ResultHandle genericType,
ResultHandle parameterAnnotations, boolean multipart,
String partType, String partFilename, String errorLocation) {
if (multipart) {
handleMultipartField(paramName, partType, partFilename, parameterType, parameterGenericType, formParamHandle,
handleMultipartField(paramName, partType, partFilename, parameterTypeStr, parameterSignature, formParamHandle,
formParams, methodCreator,
client, restClientInterfaceClassName, parameterAnnotations, genericType,
errorLocation);
} else {
BytecodeCreator notNullValue = methodCreator.ifNull(formParamHandle).falseBranch();
ResultHandle convertedFormParam = convertParamToString(notNullValue, client, formParamHandle, parameterType,
genericType, parameterAnnotations);
BytecodeCreator parameterIsStringBranch = checkStringParam(notNullValue, convertedFormParam,
restClientInterfaceClassName, errorLocation);
parameterIsStringBranch.invokeInterfaceMethod(MULTIVALUED_MAP_ADD, formParams,
notNullValue.load(paramName), convertedFormParam);
BytecodeCreator creator = methodCreator.ifNull(formParamHandle).falseBranch();
if (isCollection(parameterType, index)) {
String componentType = null;
if (parameterType.kind() == PARAMETERIZED_TYPE) {
Type paramType = parameterType.asParameterizedType().arguments().get(0);
if ((paramType.kind() == CLASS) || (paramType.kind() == PARAMETERIZED_TYPE)) {
componentType = paramType.name().toString();
}
}
if (componentType == null) {
componentType = DotNames.OBJECT.toString();
}
ResultHandle paramArray = creator.invokeStaticMethod(
MethodDescriptor.ofMethod(ToObjectArray.class, "collection", Object[].class, Collection.class),
formParamHandle);
ResultHandle convertedParamArray = creator.invokeVirtualMethod(
MethodDescriptor.ofMethod(RestClientBase.class, "convertParamArray", Object[].class, Object[].class,
Class.class, java.lang.reflect.Type.class, Annotation[].class),
client, paramArray, creator.loadClassFromTCCL(componentType), genericType, creator.newArray(
Annotation.class, 0));
creator.invokeInterfaceMethod(MULTIVALUED_MAP_ADD_ALL, formParams,
creator.load(paramName), convertedParamArray);
} else {
ResultHandle convertedFormParam = convertParamToString(creator, client, formParamHandle, parameterTypeStr,
genericType, parameterAnnotations);
BytecodeCreator parameterIsStringBranch = checkStringParam(creator, convertedFormParam,
restClientInterfaceClassName, errorLocation);
parameterIsStringBranch.invokeInterfaceMethod(MULTIVALUED_MAP_ADD, formParams,
creator.load(paramName), convertedFormParam);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package io.quarkus.rest.client.reactive;

import static org.assertj.core.api.Assertions.assertThat;

import java.net.URI;
import java.util.List;

import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;

import org.eclipse.microprofile.rest.client.RestClientBuilder;
import org.jboss.resteasy.reactive.RestForm;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import io.quarkus.test.QuarkusUnitTest;
import io.quarkus.test.common.http.TestHTTPResource;

public class FormListTest {

@RegisterExtension
static final QuarkusUnitTest config = new QuarkusUnitTest()
.withApplicationRoot((jar) -> jar.addClasses(VoidReturnTypeTest.Resource.class));

@TestHTTPResource
URI baseUri;

@Test
void testHeadersWithSubresource() {
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");
}

@Path("/test")
public static class Resource {

@POST
public String response(@RestForm List<String> input) {
return String.join("-", input);
}
}

@Path("/test")
public interface Client {

@POST
String call(@RestForm List<String> input);
}
}

0 comments on commit 1a55956

Please sign in to comment.