From b4ade630c790ed4294a1c7cf214f3b1f95d064e9 Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Thu, 20 Jan 2022 09:22:31 +0200 Subject: [PATCH] Take ParamConverterProvider into account for form params in REST Client Reactive Fixes: #23034 (cherry picked from commit 1715389569acbd87f9019eb58b24b9afa66b5c93) --- .../JaxrsClientReactiveProcessor.java | 20 +++- .../reactive/form/FormWithConverterTest.java | 91 +++++++++++++++++++ 2 files changed, 109 insertions(+), 2 deletions(-) create mode 100644 extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/form/FormWithConverterTest.java diff --git a/extensions/resteasy-reactive/jaxrs-client-reactive/deployment/src/main/java/io/quarkus/jaxrs/client/reactive/deployment/JaxrsClientReactiveProcessor.java b/extensions/resteasy-reactive/jaxrs-client-reactive/deployment/src/main/java/io/quarkus/jaxrs/client/reactive/deployment/JaxrsClientReactiveProcessor.java index dbe10d1e15610..83191b0cf23ea 100644 --- a/extensions/resteasy-reactive/jaxrs-client-reactive/deployment/src/main/java/io/quarkus/jaxrs/client/reactive/deployment/JaxrsClientReactiveProcessor.java +++ b/extensions/resteasy-reactive/jaxrs-client-reactive/deployment/src/main/java/io/quarkus/jaxrs/client/reactive/deployment/JaxrsClientReactiveProcessor.java @@ -50,6 +50,7 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedHashMap; import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.ext.ParamConverter; import javax.ws.rs.ext.ParamConverterProvider; import org.apache.http.entity.ContentType; @@ -131,6 +132,7 @@ import io.quarkus.deployment.recording.RecorderContext; import io.quarkus.deployment.util.JandexUtil; import io.quarkus.gizmo.AssignableResultHandle; +import io.quarkus.gizmo.BranchResult; import io.quarkus.gizmo.BytecodeCreator; import io.quarkus.gizmo.CatchBlockCreator; import io.quarkus.gizmo.ClassCreator; @@ -898,8 +900,22 @@ A more full example of generated client (with sub-resource) can is at the bottom invocationBuilderEnrichers.put(handleHeaderDescriptor, methodCreator.getMethodParam(paramIdx)); } else if (param.parameterType == ParameterType.FORM) { formParams = createIfAbsent(methodCreator, formParams); - methodCreator.invokeInterfaceMethod(MULTIVALUED_MAP_ADD, formParams, - methodCreator.load(param.name), methodCreator.getMethodParam(paramIdx)); + ResultHandle convertedFormParam = methodCreator.invokeVirtualMethod( + MethodDescriptor.ofMethod(RestClientBase.class, "convertParam", Object.class, Object.class, + Class.class), + methodCreator.getThis(), methodCreator.getMethodParam(paramIdx), + methodCreator.loadClass(param.type)); + ResultHandle isString = methodCreator.instanceOf(convertedFormParam, String.class); + BranchResult isStringBranch = methodCreator.ifTrue(isString); + isStringBranch.falseBranch().throwException(IllegalStateException.class, + "Form parameter '" + param.name + + "' could not be converted to 'String' for REST Client interface '" + + restClientInterface.getClassName() + "'. A proper implementation of '" + + ParamConverter.class.getName() + "' needs to be returned by a '" + + ParamConverterProvider.class.getName() + + "' that is registered with the client via the @RegisterProvider annotation on the REST Client interface."); + isStringBranch.trueBranch().invokeInterfaceMethod(MULTIVALUED_MAP_ADD, formParams, + methodCreator.load(param.name), convertedFormParam); } else if (param.parameterType == ParameterType.MULTI_PART_FORM) { if (multipartForm != null) { throw new IllegalArgumentException("MultipartForm data set twice for method " diff --git a/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/form/FormWithConverterTest.java b/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/form/FormWithConverterTest.java new file mode 100644 index 0000000000000..5d42d9f168756 --- /dev/null +++ b/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/form/FormWithConverterTest.java @@ -0,0 +1,91 @@ +package io.quarkus.rest.client.reactive.form; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; +import java.net.URI; + +import javax.ws.rs.Consumes; +import javax.ws.rs.FormParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.ext.ParamConverter; +import javax.ws.rs.ext.ParamConverterProvider; + +import org.eclipse.microprofile.rest.client.RestClientBuilder; +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 FormWithConverterTest { + + @RegisterExtension + static final QuarkusUnitTest TEST = new QuarkusUnitTest() + .withApplicationRoot((jar) -> jar + .addClasses(ResourceClient.class, Resource.class, Input.class, InputParamConverterProvider.class)); + + @TestHTTPResource + URI baseUri; + + @Test + void test() { + ResourceClient client = RestClientBuilder.newBuilder().baseUri(baseUri).register(InputParamConverterProvider.class) + .build(ResourceClient.class); + String result = client.hello(new Input("hey")); + assertThat(result).isEqualTo("hey!"); + } + + public interface ResourceClient { + + @POST + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + @Produces(MediaType.TEXT_PLAIN) + String hello(@FormParam("message") Input input); + } + + @Path("") + public static class Resource { + + @POST + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + @Produces(MediaType.TEXT_PLAIN) + public String hello(@FormParam("message") String message) { + return message + "!"; + } + } + + public static class Input { + + public String value; + + public Input(String value) { + this.value = value; + } + } + + public static class InputParamConverterProvider implements ParamConverterProvider { + @SuppressWarnings("unchecked") + @Override + public ParamConverter getConverter(Class rawType, Type genericType, Annotation[] annotations) { + if (rawType == Input.class) { + return (ParamConverter) new ParamConverter() { + @Override + public Input fromString(String value) { + return new Input(value); + } + + @Override + public String toString(Input value) { + return value.value; + } + }; + } + return null; + } + } +}