Skip to content

Commit

Permalink
Take ParamConverterProvider into account for form params in REST Clie…
Browse files Browse the repository at this point in the history
…nt Reactive

Fixes: quarkusio#23034
  • Loading branch information
geoand committed Jan 20, 2022
1 parent d666b48 commit 1715389
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 "
Expand Down
Original file line number Diff line number Diff line change
@@ -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 <T> ParamConverter<T> getConverter(Class<T> rawType, Type genericType, Annotation[] annotations) {
if (rawType == Input.class) {
return (ParamConverter<T>) new ParamConverter<Input>() {
@Override
public Input fromString(String value) {
return new Input(value);
}

@Override
public String toString(Input value) {
return value.value;
}
};
}
return null;
}
}
}

0 comments on commit 1715389

Please sign in to comment.