From be527263aa25eeee4efb90bbcb63d1f38287680e Mon Sep 17 00:00:00 2001 From: Jose Date: Mon, 29 May 2023 15:54:12 +0200 Subject: [PATCH] Support `@Encoded` annotation on REST Client Reactive 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 https://github.com/quarkusio/quarkus/issues/23961 --- .../JaxrsClientReactiveProcessor.java | 133 ++++++++++++++- .../ClientWithPathParamAndEncodedTest.java | 159 ++++++++++++++++++ .../ClientWithQueryParamAndEncodedTest.java | 149 ++++++++++++++++ .../processor/beanparam/BeanParamItem.java | 2 +- .../processor/beanparam/BeanParamParser.java | 20 ++- .../processor/beanparam/CookieParamItem.java | 2 +- .../processor/beanparam/FormParamItem.java | 3 +- .../processor/beanparam/HeaderParamItem.java | 2 +- .../client/processor/beanparam/Item.java | 8 +- .../processor/beanparam/PathParamItem.java | 5 +- .../processor/beanparam/QueryParamItem.java | 4 +- .../scanning/ClientEndpointIndexer.java | 2 + .../common/processor/EndpointIndexer.java | 1 + .../reactive/common/jaxrs/UriBuilderImpl.java | 54 +++--- .../reactive/common/model/ResourceMethod.java | 14 +- .../common/model/RestClientInterface.java | 11 ++ .../server/model/ServerResourceMethod.java | 5 +- 17 files changed, 531 insertions(+), 43 deletions(-) create mode 100644 extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/encoded/ClientWithPathParamAndEncodedTest.java create mode 100644 extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/encoded/ClientWithQueryParamAndEncodedTest.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 eb2d502468585..951e5103a2c89 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 @@ -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; @@ -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; @@ -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; @@ -806,15 +809,21 @@ A more full example of generated client (with sub-resource) can is at the bottom MethodDescriptor constructorDesc = MethodDescriptor.ofConstructor(name, WebTarget.class.getName(), List.class); try (ClassRestClientContext classContext = new ClassRestClientContext(name, constructorDesc, generatedClasses, RestClientBase.class, Closeable.class.getName(), restClientInterface.getClassName())) { - 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()) @@ -893,6 +902,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 invocationBuilderEnrichers = new HashMap<>(); @@ -903,8 +915,20 @@ A more full example of generated client (with sub-resource) can is at the bottom AssignableResultHandle formParams = null; + boolean lastEncodingEnabledByParam = true; for (int paramIdx = 0; paramIdx < method.getParameters().length; ++paramIdx) { MethodParameter param = method.getParameters()[paramIdx]; + if (!restClientInterface.isEncoded() && !method.isEncoded()) { + boolean needsDisabling = isParamAlreadyEncoded(param); + if (lastEncodingEnabledByParam && needsDisabling) { + methodCreator.assign(methodTarget, disableEncodingForWebTarget(methodCreator, methodTarget)); + lastEncodingEnabledByParam = false; + } else if (!lastEncodingEnabledByParam && !needsDisabling) { + methodCreator.assign(methodTarget, enableEncodingForWebTarget(methodCreator, methodTarget)); + lastEncodingEnabledByParam = true; + } + } + if (param.parameterType == ParameterType.QUERY) { //TODO: converters @@ -1080,6 +1104,40 @@ 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) { + return setEncodingForWebTarget(creator, baseTarget, false); + } + + private ResultHandle enableEncodingForWebTarget(BytecodeCreator creator, ResultHandle baseTarget) { + return setEncodingForWebTarget(creator, baseTarget, true); + } + + private ResultHandle setEncodingForWebTarget(BytecodeCreator creator, ResultHandle baseTarget, boolean encode) { + 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(encode)); + + return webTarget; + } + private boolean isMultipart(String[] consumes, MethodParameter[] methodParameters) { if (consumes != null) { for (String mimeType : consumes) { @@ -1201,8 +1259,16 @@ private void handleSubResourceMethod(List AssignableResultHandle constructorTarget = createWebTargetForMethod(ownerContext.constructor, ownerTarget, method); + boolean encodingEnabled = true; + FieldDescriptor forMethodTargetDesc = ownerContext.classCreator .getFieldCreator("targetInOwner" + methodIndex, WebTargetImpl.class).getFieldDescriptor(); + if (subInterface.hasDeclaredAnnotation(ENCODED)) { + ownerContext.constructor.assign(constructorTarget, + disableEncodingForWebTarget(ownerContext.constructor, constructorTarget)); + encodingEnabled = false; + } + ownerContext.constructor.writeInstanceField(forMethodTargetDesc, ownerContext.constructor.getThis(), constructorTarget); @@ -1214,9 +1280,26 @@ private void handleSubResourceMethod(List AssignableResultHandle client = createRestClientField(name, ownerContext.classCreator, ownerMethod); AssignableResultHandle webTarget = ownerMethod.createVariable(WebTarget.class); ownerMethod.assign(webTarget, ownerMethod.readInstanceField(forMethodTargetDesc, ownerMethod.getThis())); + + if (encodingEnabled && method.isEncoded()) { + ownerMethod.assign(webTarget, disableEncodingForWebTarget(ownerMethod, webTarget)); + } + // Setup Path param from current method + boolean lastEncodingEnabledByParam = true; for (int i = 0; i < method.getParameters().length; i++) { MethodParameter param = method.getParameters()[i]; + if (encodingEnabled && !method.isEncoded()) { + boolean needsDisabling = isParamAlreadyEncoded(param); + if (lastEncodingEnabledByParam && needsDisabling) { + ownerMethod.assign(webTarget, disableEncodingForWebTarget(ownerMethod, webTarget)); + lastEncodingEnabledByParam = false; + } else if (!lastEncodingEnabledByParam && !needsDisabling) { + ownerMethod.assign(webTarget, enableEncodingForWebTarget(ownerMethod, webTarget)); + lastEncodingEnabledByParam = true; + } + } + if (param.parameterType == ParameterType.PATH) { ResultHandle paramValue = ownerMethod.getMethodParam(i); // methodTarget = methodTarget.resolveTemplate(paramname, paramvalue); @@ -1310,17 +1393,34 @@ private void handleSubResourceMethod(List AssignableResultHandle methodTarget = subMethodCreator.createVariable(WebTarget.class); subMethodCreator.assign(methodTarget, subMethodCreator.readInstanceField(subMethodTarget, subMethodCreator.getThis())); + if (encodingEnabled && subMethod.isEncoded()) { + subMethodCreator.assign(methodTarget, disableEncodingForWebTarget(subMethodCreator, methodTarget)); + } ResultHandle bodyParameterValue = null; AssignableResultHandle formParams = null; Map invocationBuilderEnrichers = new HashMap<>(); + boolean lastEncodingEnabledBySubParam = true; int inheritedParamIndex = 0; for (SubResourceParameter subParamField : subParamFields) { inheritedParamIndex++; MethodParameter param = subParamField.methodParameter; ResultHandle paramValue = subMethodCreator.readInstanceField(subParamField.field, subMethodCreator.getThis()); + if (encodingEnabled && !subMethod.isEncoded()) { + boolean needsDisabling = isParamAlreadyEncoded(param); + if (lastEncodingEnabledBySubParam && needsDisabling) { + subMethodCreator.assign(methodTarget, + disableEncodingForWebTarget(subMethodCreator, methodTarget)); + lastEncodingEnabledBySubParam = false; + } else if (!lastEncodingEnabledBySubParam && !needsDisabling) { + subMethodCreator.assign(methodTarget, + enableEncodingForWebTarget(subMethodCreator, methodTarget)); + lastEncodingEnabledBySubParam = true; + } + } + if (param.parameterType == ParameterType.QUERY) { //TODO: converters @@ -1435,6 +1535,19 @@ private void handleSubResourceMethod(List // handle sub-method parameters: for (int paramIdx = 0; paramIdx < subMethod.getParameters().length; ++paramIdx) { MethodParameter param = subMethod.getParameters()[paramIdx]; + if (encodingEnabled && !subMethod.isEncoded()) { + boolean needsDisabling = isParamAlreadyEncoded(param); + if (lastEncodingEnabledBySubParam && needsDisabling) { + subMethodCreator.assign(methodTarget, + disableEncodingForWebTarget(subMethodCreator, methodTarget)); + lastEncodingEnabledBySubParam = false; + } else if (!lastEncodingEnabledBySubParam && !needsDisabling) { + subMethodCreator.assign(methodTarget, + enableEncodingForWebTarget(subMethodCreator, methodTarget)); + lastEncodingEnabledBySubParam = true; + } + } + if (param.parameterType == ParameterType.QUERY) { //TODO: converters @@ -2338,7 +2451,17 @@ private void addSubBeanParamData(MethodInfo jandexMethod, BytecodeCreator method BytecodeCreator invoEnricher = invocationBuilderEnricher.ifNotNull(invocationBuilderEnricher.getMethodParam(1)) .trueBranch(); + boolean encodingEnabled = true; for (Item item : beanParamItems) { + + if (encodingEnabled && item.isEncoded()) { + creator.assign(target, disableEncodingForWebTarget(creator, target)); + encodingEnabled = false; + } else if (!encodingEnabled && !item.isEncoded()) { + creator.assign(target, enableEncodingForWebTarget(creator, target)); + encodingEnabled = true; + } + switch (item.type()) { case BEAN_PARAM: BeanParamItem beanParamItem = (BeanParamItem) item; diff --git a/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/encoded/ClientWithPathParamAndEncodedTest.java b/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/encoded/ClientWithPathParamAndEncodedTest.java new file mode 100644 index 0000000000000..c049ca116964d --- /dev/null +++ b/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/encoded/ClientWithPathParamAndEncodedTest.java @@ -0,0 +1,159 @@ +package io.quarkus.rest.client.reactive.encoded; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.net.URI; + +import jakarta.ws.rs.Encoded; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.QueryParam; + +import org.eclipse.microprofile.rest.client.RestClientBuilder; +import org.jboss.resteasy.reactive.ClientWebApplicationException; +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 ClientWithPathParamAndEncodedTest { + + @RegisterExtension + static final QuarkusUnitTest TEST = new QuarkusUnitTest(); + + @TestHTTPResource + URI baseUri; + + @Test + public void testClientWithoutEncoded() { + ClientWithoutEncoded client = RestClientBuilder.newBuilder() + .baseUri(baseUri) + .build(ClientWithoutEncoded.class); + ClientWebApplicationException ex = assertThrows(ClientWebApplicationException.class, () -> client.call("a/b")); + assertTrue(ex.getMessage().contains("Not Found")); + } + + @Test + public void testClientWithEncodedInParameter() { + ClientWithEncodedInParameter client = RestClientBuilder.newBuilder() + .baseUri(baseUri) + .build(ClientWithEncodedInParameter.class); + assertEquals("Hello A/B", client.call("a/b")); + assertEquals("Hello A/B/C", client.sub().call("b/c")); + } + + @Test + public void testClientWithEncodedInMethod() { + ClientWithEncodedInMethod client = RestClientBuilder.newBuilder() + .baseUri(baseUri) + .build(ClientWithEncodedInMethod.class); + assertEquals("Hello A/B", client.call("a/b")); + assertEquals("Hello A/B/C", client.sub1().call("b/c")); + assertEquals("Hello A/B/C", client.sub2().call("b/c")); + assertEquals("Hello A/B/C", client.sub3().call("b/c")); + } + + @Test + public void testClientWithEncodedInClass() { + ClientWithEncodedInClass client = RestClientBuilder.newBuilder() + .baseUri(baseUri) + .build(ClientWithEncodedInClass.class); + assertEquals("Hello A/B", client.call("a/b")); + assertEquals("Hello A/B/C", client.sub().call("b/c")); + } + + @Path("/server") + public interface ClientWithoutEncoded { + @GET + @Path("/{path}") + String call(@PathParam("path") String path); + + @GET + @Path("/{path}") + String callWithQuery(@PathParam("path") String path, @QueryParam("query") String query); + } + + @Path("/server") + public interface ClientWithEncodedInParameter { + @GET + @Path("/{path}") + String call(@Encoded @PathParam("path") String path); + + @Path("/a") + SubClientWithEncodedInParameter sub(); + } + + @Path("/server") + public interface ClientWithEncodedInMethod { + @Encoded + @GET + @Path("/{path}") + String call(@PathParam("path") String path); + + @Encoded + @Path("/a") + SubClientWithoutEncoded sub1(); + + @Path("/a") + SubClientWithEncodedInMethod sub2(); + + @Path("/a") + SubClientWithEncodedInClass sub3(); + } + + @Encoded + @Path("/server") + public interface ClientWithEncodedInClass { + @GET + @Path("/{path}") + String call(@PathParam("path") String path); + + @Path("/a") + SubClientWithoutEncoded sub(); + } + + public interface SubClientWithoutEncoded { + @GET + @Path("/{path}") + String call(@PathParam("path") String path); + } + + public interface SubClientWithEncodedInMethod { + @Encoded + @GET + @Path("/{path}") + String call(@PathParam("path") String path); + } + + @Encoded + public interface SubClientWithEncodedInClass { + @GET + @Path("/{path}") + String call(@PathParam("path") String path); + } + + public interface SubClientWithEncodedInParameter { + @GET + @Path("/{path}") + String call(@Encoded @PathParam("path") String path); + } + + @Path("/server") + static class Resource { + @GET + @Path("/a/b") + public String get() { + return "Hello A/B"; + } + + @GET + @Path("/a/b/c") + public String getForSubResource() { + return "Hello A/B/C"; + } + } +} diff --git a/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/encoded/ClientWithQueryParamAndEncodedTest.java b/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/encoded/ClientWithQueryParamAndEncodedTest.java new file mode 100644 index 0000000000000..b7be2bd57674b --- /dev/null +++ b/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/encoded/ClientWithQueryParamAndEncodedTest.java @@ -0,0 +1,149 @@ +package io.quarkus.rest.client.reactive.encoded; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.net.URI; + +import jakarta.ws.rs.Encoded; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.UriInfo; + +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 ClientWithQueryParamAndEncodedTest { + + @RegisterExtension + static final QuarkusUnitTest TEST = new QuarkusUnitTest(); + + @TestHTTPResource + URI baseUri; + + @Test + public void testClientWithoutEncoded() { + ClientWithoutEncoded client = RestClientBuilder.newBuilder() + .baseUri(baseUri) + .build(ClientWithoutEncoded.class); + assertEquals("Hello query=%2524value", client.call("%24value")); + } + + @Test + public void testClientWithEncodedInParameter() { + ClientWithEncodedInParameter client = RestClientBuilder.newBuilder() + .baseUri(baseUri) + .build(ClientWithEncodedInParameter.class); + assertEquals("Hello query=%24value", client.call("%24value")); + assertEquals("Hello query1=%2524value&query2=%24value&query3=%2524value", + client.call("%24value", "%24value", "%24value")); + assertEquals("Hello subQuery=%24value", client.sub().call("%24value")); + } + + @Test + public void testClientWithEncodedInMethod() { + ClientWithEncodedInMethod client = RestClientBuilder.newBuilder() + .baseUri(baseUri) + .build(ClientWithEncodedInMethod.class); + assertEquals("Hello query=%24value", client.call("%24value")); + assertEquals("Hello subQuery=%24value", client.sub1().call("%24value")); + assertEquals("Hello subQuery=%24value", client.sub2().call("%24value")); + assertEquals("Hello subQuery=%24value", client.sub3().call("%24value")); + } + + @Test + public void testClientWithEncodedInClass() { + ClientWithEncodedInClass client = RestClientBuilder.newBuilder() + .baseUri(baseUri) + .build(ClientWithEncodedInClass.class); + assertEquals("Hello query=%24value", client.call("%24value")); + assertEquals("Hello subQuery=%24value", client.sub().call("%24value")); + } + + @Path("/server") + public interface ClientWithoutEncoded { + @GET + String call(@QueryParam("query") String query); + } + + @Path("/server") + public interface ClientWithEncodedInParameter { + @GET + String call(@Encoded @QueryParam("query") String query); + + @GET + String call(@QueryParam("query1") String query1, @Encoded @QueryParam("query2") String query2, + @QueryParam("query3") String query3); + + @Path("/a") + SubClientWithEncodedInParameter sub(); + } + + @Path("/server") + public interface ClientWithEncodedInMethod { + @Encoded + @GET + String call(@QueryParam("query") String query); + + @Encoded + @Path("/a") + SubClientWithoutEncoded sub1(); + + @Path("/a") + SubClientWithEncodedInMethod sub2(); + + @Path("/a") + SubClientWithEncodedInClass sub3(); + } + + @Encoded + @Path("/server") + public interface ClientWithEncodedInClass { + @GET + String call(@QueryParam("query") String query); + + @Path("/a") + SubClientWithoutEncoded sub(); + } + + public interface SubClientWithoutEncoded { + @GET + String call(@QueryParam("subQuery") String subQuery); + } + + @Encoded + public interface SubClientWithEncodedInClass { + @GET + String call(@QueryParam("subQuery") String subQuery); + } + + public interface SubClientWithEncodedInMethod { + @Encoded + @GET + String call(@QueryParam("subQuery") String subQuery); + } + + public interface SubClientWithEncodedInParameter { + @GET + String call(@Encoded @QueryParam("subQuery") String subQuery); + } + + @Path("/server") + static class Resource { + @GET + public String get(@Context UriInfo uriInfo) { + return "Hello " + uriInfo.getRequestUri().getRawQuery(); + } + + @GET + @Path("/a") + public String getFromA(@Context UriInfo uriInfo) { + return "Hello " + uriInfo.getRequestUri().getRawQuery(); + } + } +} diff --git a/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/BeanParamItem.java b/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/BeanParamItem.java index 35abc4465f858..cad40a43b17d8 100644 --- a/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/BeanParamItem.java +++ b/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/BeanParamItem.java @@ -7,7 +7,7 @@ public class BeanParamItem extends Item { private final String className; public BeanParamItem(String fieldName, List items, String className, ValueExtractor extractor) { - super(fieldName, ItemType.BEAN_PARAM, extractor); + super(fieldName, ItemType.BEAN_PARAM, false, extractor); this.items = items; this.className = className; } 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 b85ccd9813516..fa2a9595cf73c 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 @@ -2,6 +2,7 @@ import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.BEAN_PARAM; import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.COOKIE_PARAM; +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.HEADER_PARAM; import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.PATH_PARAM; @@ -62,19 +63,23 @@ private static List parseInternal(ClassInfo beanParamClass, IndexView inde resultList.addAll(paramItemsForFieldsAndMethods(beanParamClass, QUERY_PARAM, (annotationValue, fieldInfo) -> new QueryParamItem(fieldInfo.name(), annotationValue, + fieldInfo.hasDeclaredAnnotation(ENCODED), new FieldExtractor(null, fieldInfo.name(), fieldInfo.declaringClass().name().toString()), fieldInfo.type()), (annotationValue, getterMethod) -> new QueryParamItem(getterMethod.name(), annotationValue, + getterMethod.hasDeclaredAnnotation(ENCODED), new GetterExtractor(getterMethod), getterMethod.returnType()))); resultList.addAll(paramItemsForFieldsAndMethods(beanParamClass, REST_QUERY_PARAM, (annotationValue, fieldInfo) -> new QueryParamItem(fieldInfo.name(), annotationValue != null ? annotationValue : fieldInfo.name(), + fieldInfo.hasDeclaredAnnotation(ENCODED), new FieldExtractor(null, fieldInfo.name(), fieldInfo.declaringClass().name().toString()), fieldInfo.type()), (annotationValue, getterMethod) -> new QueryParamItem(getterMethod.name(), annotationValue != null ? annotationValue : getterName(getterMethod), + getterMethod.hasDeclaredAnnotation(ENCODED), new GetterExtractor(getterMethod), getterMethod.returnType()))); @@ -139,32 +144,33 @@ private static List parseInternal(ClassInfo beanParamClass, IndexView inde resultList.addAll(paramItemsForFieldsAndMethods(beanParamClass, PATH_PARAM, (annotationValue, fieldInfo) -> new PathParamItem(fieldInfo.name(), annotationValue, - fieldInfo.type().name().toString(), + fieldInfo.type().name().toString(), fieldInfo.hasDeclaredAnnotation(ENCODED), new FieldExtractor(null, fieldInfo.name(), fieldInfo.declaringClass().name().toString())), (annotationValue, getterMethod) -> new PathParamItem(getterMethod.name(), annotationValue, - getterMethod.returnType().name().toString(), + getterMethod.returnType().name().toString(), getterMethod.hasDeclaredAnnotation(ENCODED), new GetterExtractor(getterMethod)))); resultList.addAll(paramItemsForFieldsAndMethods(beanParamClass, REST_PATH_PARAM, (annotationValue, fieldInfo) -> new PathParamItem(fieldInfo.name(), annotationValue != null ? annotationValue : fieldInfo.name(), fieldInfo.type().name().toString(), + fieldInfo.hasDeclaredAnnotation(ENCODED), new FieldExtractor(null, fieldInfo.name(), fieldInfo.declaringClass().name().toString())), (annotationValue, getterMethod) -> new PathParamItem(getterMethod.name(), annotationValue != null ? annotationValue : getterName(getterMethod), - getterMethod.returnType().name().toString(), + getterMethod.returnType().name().toString(), getterMethod.hasDeclaredAnnotation(ENCODED), new GetterExtractor(getterMethod)))); resultList.addAll(paramItemsForFieldsAndMethods(beanParamClass, FORM_PARAM, (annotationValue, fieldInfo) -> new FormParamItem(fieldInfo.name(), annotationValue, fieldInfo.type().name().toString(), AsmUtil.getSignature(fieldInfo.type()), fieldInfo.name(), - partType(fieldInfo), fileName(fieldInfo), + 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(), AsmUtil.getSignature(getterMethod.returnType()), getterMethod.name(), - partType(getterMethod), fileName(getterMethod), + partType(getterMethod), fileName(getterMethod), getterMethod.hasDeclaredAnnotation(ENCODED), new GetterExtractor(getterMethod)))); resultList.addAll(paramItemsForFieldsAndMethods(beanParamClass, REST_FORM_PARAM, @@ -172,14 +178,14 @@ private static List parseInternal(ClassInfo beanParamClass, IndexView inde annotationValue != null ? annotationValue : fieldInfo.name(), fieldInfo.type().name().toString(), AsmUtil.getSignature(fieldInfo.type()), fieldInfo.name(), - partType(fieldInfo), fileName(fieldInfo), + 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(), AsmUtil.getSignature(getterMethod.returnType()), getterMethod.name(), - partType(getterMethod), fileName(getterMethod), + partType(getterMethod), fileName(getterMethod), getterMethod.hasDeclaredAnnotation(ENCODED), new GetterExtractor(getterMethod)))); return resultList; diff --git a/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/CookieParamItem.java b/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/CookieParamItem.java index ba068e0ad463f..10768d8376158 100644 --- a/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/CookieParamItem.java +++ b/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/CookieParamItem.java @@ -5,7 +5,7 @@ public class CookieParamItem extends Item { private final String paramType; public CookieParamItem(String fieldName, String cookieName, ValueExtractor extractor, String paramType) { - super(fieldName, ItemType.COOKIE, extractor); + super(fieldName, ItemType.COOKIE, false, extractor); this.cookieName = cookieName; this.paramType = paramType; } 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 60c2fe9d3ccb0..2fada96647f7c 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 @@ -12,8 +12,9 @@ public class FormParamItem extends Item { public FormParamItem(String fieldName, String formParamName, String paramType, String paramSignature, String sourceName, String mimeType, String fileName, + boolean encoded, ValueExtractor valueExtractor) { - super(fieldName, ItemType.FORM_PARAM, valueExtractor); + super(fieldName, ItemType.FORM_PARAM, encoded, valueExtractor); this.formParamName = formParamName; this.paramType = paramType; this.paramSignature = paramSignature; diff --git a/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/HeaderParamItem.java b/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/HeaderParamItem.java index 61b417b3865ff..79c6adaf83c18 100644 --- a/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/HeaderParamItem.java +++ b/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/HeaderParamItem.java @@ -5,7 +5,7 @@ public class HeaderParamItem extends Item { private final String paramType; public HeaderParamItem(String fieldName, String headerName, ValueExtractor extractor, String paramType) { - super(fieldName, ItemType.HEADER_PARAM, extractor); + super(fieldName, ItemType.HEADER_PARAM, false, extractor); this.headerName = headerName; this.paramType = paramType; } diff --git a/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/Item.java b/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/Item.java index 1ef10511912ad..6cef2386dad8c 100644 --- a/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/Item.java +++ b/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/Item.java @@ -7,11 +7,13 @@ public abstract class Item { private final String fieldName; private final ItemType type; + private final boolean encoded; private final ValueExtractor valueExtractor; - public Item(String fieldName, ItemType type, ValueExtractor valueExtractor) { + public Item(String fieldName, ItemType type, boolean encoded, ValueExtractor valueExtractor) { this.fieldName = fieldName; this.type = type; + this.encoded = encoded; this.valueExtractor = valueExtractor; } @@ -23,6 +25,10 @@ public ItemType type() { return type; } + public boolean isEncoded() { + return encoded; + } + public ResultHandle extract(BytecodeCreator methodCreator, ResultHandle param) { return valueExtractor.extract(methodCreator, param); } diff --git a/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/PathParamItem.java b/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/PathParamItem.java index 474052a4f0a39..6ca98452dfc92 100644 --- a/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/PathParamItem.java +++ b/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/PathParamItem.java @@ -5,8 +5,9 @@ public class PathParamItem extends Item { private final String pathParamName; private final String paramType; - public PathParamItem(String fieldName, String pathParamName, String paramType, ValueExtractor valueExtractor) { - super(fieldName, ItemType.PATH_PARAM, valueExtractor); + public PathParamItem(String fieldName, String pathParamName, String paramType, boolean encoded, + ValueExtractor valueExtractor) { + super(fieldName, ItemType.PATH_PARAM, encoded, valueExtractor); this.pathParamName = pathParamName; this.paramType = paramType; } diff --git a/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/QueryParamItem.java b/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/QueryParamItem.java index a3b83a979d817..56641b51c69f7 100644 --- a/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/QueryParamItem.java +++ b/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/QueryParamItem.java @@ -7,8 +7,8 @@ public class QueryParamItem extends Item { private final String name; private final Type valueType; - public QueryParamItem(String fieldName, String name, ValueExtractor extractor, Type valueType) { - super(fieldName, ItemType.QUERY_PARAM, extractor); + public QueryParamItem(String fieldName, String name, boolean encoded, ValueExtractor extractor, Type valueType) { + super(fieldName, ItemType.QUERY_PARAM, encoded, extractor); this.name = name; this.valueType = valueType; } diff --git a/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/scanning/ClientEndpointIndexer.java b/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/scanning/ClientEndpointIndexer.java index eaba90c22749c..550902548acae 100644 --- a/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/scanning/ClientEndpointIndexer.java +++ b/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/scanning/ClientEndpointIndexer.java @@ -1,6 +1,7 @@ package org.jboss.resteasy.reactive.client.processor.scanning; import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; +import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.ENCODED; import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.JSONP_JSON_ARRAY; import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.JSONP_JSON_NUMBER; import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.JSONP_JSON_OBJECT; @@ -64,6 +65,7 @@ public MaybeRestClientInterface createClientProxy(ClassInfo classInfo, try { RestClientInterface clazz = new RestClientInterface(); clazz.setClassName(classInfo.name().toString()); + clazz.setEncoded(classInfo.hasDeclaredAnnotation(ENCODED)); if (path != null) { if (!path.startsWith("/")) { path = "/" + path; diff --git a/independent-projects/resteasy-reactive/common/processor/src/main/java/org/jboss/resteasy/reactive/common/processor/EndpointIndexer.java b/independent-projects/resteasy-reactive/common/processor/src/main/java/org/jboss/resteasy/reactive/common/processor/EndpointIndexer.java index e52a18d68850a..1ecf00262239b 100644 --- a/independent-projects/resteasy-reactive/common/processor/src/main/java/org/jboss/resteasy/reactive/common/processor/EndpointIndexer.java +++ b/independent-projects/resteasy-reactive/common/processor/src/main/java/org/jboss/resteasy/reactive/common/processor/EndpointIndexer.java @@ -756,6 +756,7 @@ private ResourceMethod createResourceMethod(ClassInfo currentClassInfo, ClassInf .setRunOnVirtualThread(runOnVirtualThread) .setSuspended(suspended) .setSse(sse) + .setEncoded(currentMethodInfo.hasDeclaredAnnotation(ENCODED)) .setStreamElementType(streamElementType) .setFormParamRequired(formParamRequired) .setFileFormNames(fileFormNames) diff --git a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/jaxrs/UriBuilderImpl.java b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/jaxrs/UriBuilderImpl.java index 710bff12906e2..94a860b34fd34 100644 --- a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/jaxrs/UriBuilderImpl.java +++ b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/jaxrs/UriBuilderImpl.java @@ -66,6 +66,7 @@ public boolean containsKey(Object key) { private String fragment; private String ssp; private String authority; + private boolean encode = true; private MultiQueryParamMode queryParamMode = MultiQueryParamMode.MULTI_PAIRS; @@ -81,6 +82,7 @@ public UriBuilder clone() { impl.ssp = ssp; impl.authority = authority; impl.queryParamMode = queryParamMode; + impl.encode = encode; return impl; } @@ -350,6 +352,11 @@ public UriBuilder port(int port) throws IllegalArgumentException { return this; } + public UriBuilder encode(boolean encode) { + this.encode = encode; + return this; + } + protected static String paths(boolean encode, String basePath, String... segments) { String path = basePath; if (path == null) @@ -385,7 +392,7 @@ protected static String paths(boolean encode, String basePath, String... segment public UriBuilder path(String segment) throws IllegalArgumentException { if (segment == null) throw new IllegalArgumentException("path is null"); - path = paths(true, path, segment); + path = paths(encode, path, segment); return this; } @@ -429,7 +436,7 @@ public UriBuilder path(Method method) throws IllegalArgumentException { } Path ann = method.getAnnotation(Path.class); if (ann != null) { - path = paths(true, path, ann.value()); + path = paths(encode, path, ann.value()); } else { throw new IllegalArgumentException("Method not annotated with @Path"); } @@ -552,7 +559,7 @@ private CharSequence buildCharSequence(Map paramMap, b } if (path != null) { StringBuilder tmp = new StringBuilder(); - replaceParameter(paramMap, fromEncodedMap, isTemplate, path, tmp, encodeSlash); + replaceParameter(paramMap, fromEncodedMap, isTemplate, path, tmp, encode, encodeSlash); if (userInfo != null || host != null) { if (tmp.length() > 0 && tmp.charAt(0) != '/') builder.append("/"); @@ -605,6 +612,11 @@ public static Matcher createUriParamMatcher(String string) { protected StringBuilder replaceParameter(Map paramMap, boolean fromEncodedMap, boolean isTemplate, String string, StringBuilder builder, boolean encodeSlash) { + return replaceParameter(paramMap, fromEncodedMap, isTemplate, string, builder, true, encodeSlash); + } + + protected StringBuilder replaceParameter(Map paramMap, boolean fromEncodedMap, boolean isTemplate, + String string, StringBuilder builder, boolean encode, boolean encodeSlash) { if (string.indexOf('{') == -1) { return builder.append(string); } @@ -624,7 +636,11 @@ protected StringBuilder replaceParameter(Map paramMap, } Object value = paramMap.get(param); String stringValue = value != null ? value.toString() : null; - if (stringValue != null) { + if (stringValue == null) { + throw new IllegalArgumentException("Template parameter null: " + param); + } + + if (encode) { if (!fromEncodedMap) { if (encodeSlash) stringValue = Encode.encodePathSegmentAsIs(stringValue); @@ -636,11 +652,10 @@ protected StringBuilder replaceParameter(Map paramMap, else stringValue = Encode.encodePathSaveEncodings(stringValue); } - builder.append(stringValue); - start = matcher.end(); - } else { - throw new IllegalArgumentException("Template parameter null: " + param); } + + builder.append(stringValue); + start = matcher.end(); } builder.append(string, start, string.length()); return builder; @@ -882,29 +897,29 @@ public UriBuilder clientQueryParam(String name, Object... values) throws Illegal if (values == null) throw new IllegalArgumentException("Values parameter is null"); + String queryParamName = encode ? Encode.encodeQueryParamAsIs(name) : name; if (queryParamMode == MultiQueryParamMode.COMMA_SEPARATED) { - sb.append(Encode.encodeQueryParamAsIs(name)).append("="); + sb.append(queryParamName).append("="); } for (Object value : values) { if (value == null) throw new IllegalArgumentException("Value is null"); sb.append(prefix); + String queryParamValue = encode ? Encode.encodeQueryParamAsIs(value.toString()) : value.toString(); switch (queryParamMode) { case MULTI_PAIRS: prefix = "&"; - sb.append(Encode.encodeQueryParamAsIs(name)).append("=") - .append(Encode.encodeQueryParamAsIs(value.toString())); + sb.append(queryParamName).append("=").append(queryParamValue); break; case COMMA_SEPARATED: prefix = ","; - sb.append(Encode.encodeQueryParamAsIs(value.toString())); + sb.append(queryParamValue); break; case ARRAY_PAIRS: prefix = "&"; String queryParamConnector = arrayPairsConnector(values); - sb.append(Encode.encodeQueryParamAsIs(name)).append(queryParamConnector) - .append(Encode.encodeQueryParamAsIs(value.toString())); + sb.append(queryParamName).append(queryParamConnector).append(queryParamValue); break; } } @@ -927,28 +942,29 @@ public UriBuilder queryParam(String name, Object... values) throws IllegalArgume if (values == null) throw new IllegalArgumentException("Values parameter is null"); + String queryParamName = encode ? Encode.encodeQueryParam(name) : name; if (queryParamMode == MultiQueryParamMode.COMMA_SEPARATED) { - sb.append(Encode.encodeQueryParam(name)).append("="); + sb.append(queryParamName).append("="); } for (Object value : values) { if (value == null) throw new IllegalArgumentException("Value is null"); sb.append(prefix); + String queryParamValue = encode ? Encode.encodeQueryParam(value.toString()) : value.toString(); switch (queryParamMode) { case MULTI_PAIRS: prefix = "&"; - sb.append(Encode.encodeQueryParam(name)).append("=").append(Encode.encodeQueryParam(value.toString())); + sb.append(queryParamName).append("=").append(queryParamValue); break; case COMMA_SEPARATED: prefix = ","; - sb.append(Encode.encodeQueryParam(value.toString())); + sb.append(queryParamValue); break; case ARRAY_PAIRS: prefix = "&"; String queryParamConnector = arrayPairsConnector(values); - sb.append(Encode.encodeQueryParam(name)).append(queryParamConnector) - .append(Encode.encodeQueryParam(value.toString())); + sb.append(queryParamName).append(queryParamConnector).append(queryParamValue); break; } } diff --git a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/model/ResourceMethod.java b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/model/ResourceMethod.java index 37baf4b5c0d4f..90d07e3d351d4 100644 --- a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/model/ResourceMethod.java +++ b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/model/ResourceMethod.java @@ -72,13 +72,15 @@ public class ResourceMethod { private List subResourceMethods; + private boolean encoded; + public ResourceMethod() { } public ResourceMethod(String httpMethod, String path, String[] produces, String streamElementType, String[] consumes, Set nameBindingNames, String name, String returnType, String simpleReturnType, MethodParameter[] parameters, boolean blocking, boolean suspended, boolean isSse, boolean isFormParamRequired, - List subResourceMethods) { + List subResourceMethods, boolean encoded) { this.httpMethod = httpMethod; this.path = path; this.produces = produces; @@ -94,6 +96,7 @@ public ResourceMethod(String httpMethod, String path, String[] produces, String this.isSse = isSse; this.isFormParamRequired = isFormParamRequired; this.subResourceMethods = subResourceMethods; + this.encoded = encoded; } public boolean isResourceLocator() { @@ -244,6 +247,15 @@ public String getStreamElementType() { return streamElementType; } + public boolean isEncoded() { + return encoded; + } + + public ResourceMethod setEncoded(boolean encoded) { + this.encoded = encoded; + return this; + } + @Override public String toString() { if (httpMethod != null) diff --git a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/model/RestClientInterface.java b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/model/RestClientInterface.java index cdbcb3e63c7c8..63e16560010db 100644 --- a/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/model/RestClientInterface.java +++ b/independent-projects/resteasy-reactive/common/runtime/src/main/java/org/jboss/resteasy/reactive/common/model/RestClientInterface.java @@ -26,6 +26,8 @@ public class RestClientInterface { private Set pathParameters = new HashSet<>(); + private boolean encoded = false; + public String getClassName() { return className; } @@ -60,4 +62,13 @@ public RestClientInterface setPathParameters(Set pathParameters) { this.pathParameters = pathParameters; return this; } + + public boolean isEncoded() { + return encoded; + } + + public RestClientInterface setEncoded(boolean encoded) { + this.encoded = encoded; + return this; + } } diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/model/ServerResourceMethod.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/model/ServerResourceMethod.java index 89c406a8837e6..9c8620e9da341 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/model/ServerResourceMethod.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/model/ServerResourceMethod.java @@ -26,9 +26,10 @@ public ServerResourceMethod(String httpMethod, String path, String[] produces, S Set nameBindingNames, String name, String returnType, String simpleReturnType, MethodParameter[] parameters, boolean blocking, boolean suspended, boolean sse, boolean formParamRequired, List subResourceMethods, Supplier invoker, Set methodAnnotationNames, - List handlerChainCustomizers, ParameterExtractor customerParameterExtractor) { + List handlerChainCustomizers, ParameterExtractor customerParameterExtractor, + boolean encoded) { super(httpMethod, path, produces, streamElementType, consumes, nameBindingNames, name, returnType, simpleReturnType, - parameters, blocking, suspended, sse, formParamRequired, subResourceMethods); + parameters, blocking, suspended, sse, formParamRequired, subResourceMethods, encoded); this.invoker = invoker; this.methodAnnotationNames = methodAnnotationNames; this.handlerChainCustomizers = handlerChainCustomizers;