Skip to content

Commit

Permalink
Support @Encoded annotation on REST Client Reactive
Browse files Browse the repository at this point in the history
These changes add support for the `@Encoded` annotation for PATH and QUERY params. 

As stated in the Encoded annotation javadocs, we can use this annotation at class and method level too, so we can use it in REST Client reactive like this. 

Fix quarkusio#23961
  • Loading branch information
Sgitario committed May 29, 2023
1 parent 29d71ec commit 0e56fd0
Show file tree
Hide file tree
Showing 13 changed files with 417 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import static org.jboss.resteasy.reactive.common.processor.EndpointIndexer.extractProducesConsumesValues;
import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.COMPLETION_STAGE;
import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.CONSUMES;
import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.ENCODED;
import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.FORM_PARAM;
import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.MULTI;
import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.OBJECT;
Expand Down Expand Up @@ -58,6 +59,7 @@
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.MultivaluedHashMap;
import jakarta.ws.rs.core.MultivaluedMap;
import jakarta.ws.rs.core.UriBuilder;
import jakarta.ws.rs.ext.ParamConverter;
import jakarta.ws.rs.ext.ParamConverterProvider;

Expand Down Expand Up @@ -100,6 +102,7 @@
import org.jboss.resteasy.reactive.common.core.GenericTypeMapping;
import org.jboss.resteasy.reactive.common.core.ResponseBuilderFactory;
import org.jboss.resteasy.reactive.common.core.Serialisers;
import org.jboss.resteasy.reactive.common.jaxrs.UriBuilderImpl;
import org.jboss.resteasy.reactive.common.model.MaybeRestClientInterface;
import org.jboss.resteasy.reactive.common.model.MethodParameter;
import org.jboss.resteasy.reactive.common.model.ParameterType;
Expand Down Expand Up @@ -810,11 +813,18 @@ A more full example of generated client (with sub-resource) can is at the bottom
classContext.constructor.invokeSpecialMethod(MethodDescriptor.ofConstructor(RestClientBase.class, List.class),
classContext.constructor.getThis(), classContext.constructor.getMethodParam(1));

AssignableResultHandle baseTarget = classContext.constructor.createVariable(WebTarget.class);
AssignableResultHandle baseTarget = classContext.constructor.createVariable(WebTargetImpl.class);
if (restClientInterface.isEncoded()) {
classContext.constructor.assign(baseTarget,
disableEncodingForWebTarget(classContext.constructor, classContext.constructor.getMethodParam(0)));
} else {
classContext.constructor.assign(baseTarget, classContext.constructor.getMethodParam(0));
}

classContext.constructor.assign(baseTarget,
classContext.constructor.invokeInterfaceMethod(
MethodDescriptor.ofMethod(WebTarget.class, "path", WebTarget.class, String.class),
classContext.constructor.getMethodParam(0),
classContext.constructor.invokeVirtualMethod(
MethodDescriptor.ofMethod(WebTargetImpl.class, "path", WebTargetImpl.class, String.class),
baseTarget,
classContext.constructor.load(restClientInterface.getPath())));
FieldDescriptor baseTargetField = classContext.classCreator
.getFieldCreator("baseTarget", WebTargetImpl.class.getName())
Expand Down Expand Up @@ -893,6 +903,9 @@ A more full example of generated client (with sub-resource) can is at the bottom
AssignableResultHandle methodTarget = methodCreator.createVariable(WebTarget.class);
methodCreator.assign(methodTarget,
methodCreator.readInstanceField(webTargetForMethod, methodCreator.getThis()));
if (!restClientInterface.isEncoded() && method.isEncoded()) {
methodCreator.assign(methodTarget, disableEncodingForWebTarget(methodCreator, methodTarget));
}

Integer bodyParameterIdx = null;
Map<MethodDescriptor, ResultHandle> invocationBuilderEnrichers = new HashMap<>();
Expand All @@ -905,6 +918,11 @@ A more full example of generated client (with sub-resource) can is at the bottom

for (int paramIdx = 0; paramIdx < method.getParameters().length; ++paramIdx) {
MethodParameter param = method.getParameters()[paramIdx];

if (!restClientInterface.isEncoded() && !method.isEncoded() && isParamAlreadyEncoded(param)) {
methodCreator.assign(methodTarget, disableEncodingForWebTarget(methodCreator, methodTarget));
}

if (param.parameterType == ParameterType.QUERY) {
//TODO: converters

Expand Down Expand Up @@ -1080,6 +1098,32 @@ A more full example of generated client (with sub-resource) can is at the bottom

}

/**
* The @Encoded annotation is only supported in path/query/matrix/form params.
*/
private boolean isParamAlreadyEncoded(MethodParameter param) {
return param.encoded
&& (param.parameterType == ParameterType.PATH
|| param.parameterType == ParameterType.QUERY
|| param.parameterType == ParameterType.FORM
|| param.parameterType == ParameterType.MATRIX);
}

private ResultHandle disableEncodingForWebTarget(BytecodeCreator creator, ResultHandle baseTarget) {
ResultHandle webTarget = creator.invokeVirtualMethod(
MethodDescriptor.ofMethod(WebTargetImpl.class, "clone", WebTargetImpl.class), baseTarget);

ResultHandle uriBuilderImpl = creator.invokeVirtualMethod(
MethodDescriptor.ofMethod(WebTargetImpl.class, "getUriBuilderUnsafe", UriBuilderImpl.class),
webTarget);

creator.invokeVirtualMethod(
MethodDescriptor.ofMethod(UriBuilderImpl.class, "encode", UriBuilder.class, boolean.class),
uriBuilderImpl, creator.load(false));

return webTarget;
}

private boolean isMultipart(String[] consumes, MethodParameter[] methodParameters) {
if (consumes != null) {
for (String mimeType : consumes) {
Expand Down Expand Up @@ -1201,8 +1245,15 @@ private void handleSubResourceMethod(List<JaxrsClientReactiveEnricherBuildItem>
AssignableResultHandle constructorTarget = createWebTargetForMethod(ownerContext.constructor, ownerTarget,
method);

boolean subRestClientIsEncoded = subInterface.hasDeclaredAnnotation(ENCODED);

FieldDescriptor forMethodTargetDesc = ownerContext.classCreator
.getFieldCreator("targetInOwner" + methodIndex, WebTargetImpl.class).getFieldDescriptor();
if (subRestClientIsEncoded) {
ownerContext.constructor.assign(constructorTarget,
disableEncodingForWebTarget(ownerContext.constructor, constructorTarget));
}

ownerContext.constructor.writeInstanceField(forMethodTargetDesc, ownerContext.constructor.getThis(),
constructorTarget);

Expand All @@ -1214,9 +1265,19 @@ private void handleSubResourceMethod(List<JaxrsClientReactiveEnricherBuildItem>
AssignableResultHandle client = createRestClientField(name, ownerContext.classCreator, ownerMethod);
AssignableResultHandle webTarget = ownerMethod.createVariable(WebTarget.class);
ownerMethod.assign(webTarget, ownerMethod.readInstanceField(forMethodTargetDesc, ownerMethod.getThis()));

if (!subRestClientIsEncoded && method.isEncoded()) {
ownerMethod.assign(webTarget, disableEncodingForWebTarget(ownerMethod, webTarget));
}

// Setup Path param from current method
for (int i = 0; i < method.getParameters().length; i++) {
MethodParameter param = method.getParameters()[i];

if (!subRestClientIsEncoded && !method.isEncoded() && isParamAlreadyEncoded(param)) {
ownerMethod.assign(webTarget, disableEncodingForWebTarget(ownerMethod, webTarget));
}

if (param.parameterType == ParameterType.PATH) {
ResultHandle paramValue = ownerMethod.getMethodParam(i);
// methodTarget = methodTarget.resolveTemplate(paramname, paramvalue);
Expand Down Expand Up @@ -1310,6 +1371,9 @@ private void handleSubResourceMethod(List<JaxrsClientReactiveEnricherBuildItem>
AssignableResultHandle methodTarget = subMethodCreator.createVariable(WebTarget.class);
subMethodCreator.assign(methodTarget,
subMethodCreator.readInstanceField(subMethodTarget, subMethodCreator.getThis()));
if (!subRestClientIsEncoded && subMethod.isEncoded()) {
subMethodCreator.assign(methodTarget, disableEncodingForWebTarget(subMethodCreator, methodTarget));
}

ResultHandle bodyParameterValue = null;
AssignableResultHandle formParams = null;
Expand All @@ -1321,6 +1385,11 @@ private void handleSubResourceMethod(List<JaxrsClientReactiveEnricherBuildItem>
MethodParameter param = subParamField.methodParameter;
ResultHandle paramValue = subMethodCreator.readInstanceField(subParamField.field,
subMethodCreator.getThis());

if (!subRestClientIsEncoded && !subMethod.isEncoded() && isParamAlreadyEncoded(param)) {
subMethodCreator.assign(methodTarget, disableEncodingForWebTarget(subMethodCreator, methodTarget));
}

if (param.parameterType == ParameterType.QUERY) {
//TODO: converters

Expand Down Expand Up @@ -1435,6 +1504,10 @@ private void handleSubResourceMethod(List<JaxrsClientReactiveEnricherBuildItem>
// handle sub-method parameters:
for (int paramIdx = 0; paramIdx < subMethod.getParameters().length; ++paramIdx) {
MethodParameter param = subMethod.getParameters()[paramIdx];
if (!subRestClientIsEncoded && !subMethod.isEncoded() && isParamAlreadyEncoded(param)) {
subMethodCreator.assign(methodTarget, disableEncodingForWebTarget(subMethodCreator, methodTarget));
}

if (param.parameterType == ParameterType.QUERY) {
//TODO: converters

Expand Down Expand Up @@ -2381,6 +2454,10 @@ private void addSubBeanParamData(MethodInfo jandexMethod, BytecodeCreator method
break;
case PATH_PARAM:
PathParamItem pathParam = (PathParamItem) item;
if (pathParam.isEncoded()) {
creator.assign(target, disableEncodingForWebTarget(creator, target));
}

addPathParam(creator, target,
pathParam.getPathParamName(),
pathParam.extract(creator, param), pathParam.getParamType(), client,
Expand All @@ -2389,6 +2466,10 @@ private void addSubBeanParamData(MethodInfo jandexMethod, BytecodeCreator method
break;
case FORM_PARAM:
FormParamItem formParam = (FormParamItem) item;
if (formParam.isEncoded()) {
creator.assign(target, disableEncodingForWebTarget(creator, target));
}

addFormParam(creator, formParam.getFormParamName(), formParam.extract(creator, param),
formParam.getParamType(), formParam.getParamSignature(), restClientInterfaceClassName, client,
formParams,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package io.quarkus.rest.client.reactive.encoded;

import static org.junit.jupiter.api.Assertions.assertEquals;

import java.net.URI;

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

import io.quarkus.rest.client.reactive.beanparam.BeanFormParamTest;
import io.quarkus.test.QuarkusUnitTest;
import io.quarkus.test.common.http.TestHTTPResource;
import jakarta.ws.rs.BeanParam;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.Encoded;
import jakarta.ws.rs.FormParam;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.UriInfo;

public class ClientWithFormParamAndEncodedTest {

@RegisterExtension
static final QuarkusUnitTest TEST = new QuarkusUnitTest();

@TestHTTPResource
URI baseUri;

@Test
public void testClientWithoutEncoded() {
ClientWithoutEncoded client = RestClientBuilder.newBuilder()
.baseUri(baseUri)
.build(ClientWithoutEncoded.class);
assertEquals("received %24value-%24value", client.call(new BeanWithFormParams("%24value")));
}

public static class BeanWithFormParams {
private final String value;

public BeanWithFormParams(String value) {
this.value = value;
}

@FormParam("param1")
public String getWithoutEncoded() {
return value;
}

@Encoded
@FormParam("param2")
public String getWithEncoded() {
return value;
}
}

@Path("/server")
public interface ClientWithoutEncoded {
@POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
String call(@BeanParam BeanWithFormParams beanParam);
}

@Path("/server")
static class Resource {
@POST
public String post(@FormParam("param1") String param1, @FormParam("param2") String param2,
@Context ResteasyReactiveRequestContext context) {
return String.format("received %s-%s", param1, param2);
}
}
}
Loading

0 comments on commit 0e56fd0

Please sign in to comment.