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 dbe10d1e15610d..58cd3ea85b5b31 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 @@ -79,6 +79,7 @@ import org.jboss.resteasy.reactive.client.processor.beanparam.BeanParamItem; import org.jboss.resteasy.reactive.client.processor.beanparam.ClientBeanParamInfo; import org.jboss.resteasy.reactive.client.processor.beanparam.CookieParamItem; +import org.jboss.resteasy.reactive.client.processor.beanparam.FormParamItem; import org.jboss.resteasy.reactive.client.processor.beanparam.HeaderParamItem; import org.jboss.resteasy.reactive.client.processor.beanparam.Item; import org.jboss.resteasy.reactive.client.processor.beanparam.PathParamItem; @@ -849,11 +850,12 @@ A more full example of generated client (with sub-resource) can is at the bottom AssignableResultHandle invocationBuilderRef = handleBeanParamMethod .createVariable(Invocation.Builder.class); handleBeanParamMethod.assign(invocationBuilderRef, handleBeanParamMethod.getMethodParam(0)); - addBeanParamData(methodCreator, handleBeanParamMethod, + formParams = addBeanParamData(methodCreator, handleBeanParamMethod, invocationBuilderRef, beanParam.getItems(), methodCreator.getMethodParam(paramIdx), methodTarget, index, methodCreator.getThis(), - handleBeanParamMethod.getThis()); + handleBeanParamMethod.getThis(), + formParams); handleBeanParamMethod.returnValue(invocationBuilderRef); invocationBuilderEnrichers.put(handleBeanParamDescriptor, methodCreator.getMethodParam(paramIdx)); @@ -1126,12 +1128,13 @@ private void handleSubResourceMethod(List AssignableResultHandle invocationBuilderRef = handleBeanParamMethod .createVariable(Invocation.Builder.class); handleBeanParamMethod.assign(invocationBuilderRef, handleBeanParamMethod.getMethodParam(0)); - addBeanParamData(subMethodCreator, handleBeanParamMethod, + formParams = addBeanParamData(subMethodCreator, handleBeanParamMethod, invocationBuilderRef, beanParam.getItems(), paramValue, methodTarget, index, subMethodCreator.readInstanceField(clientField, subMethodCreator.getThis()), handleBeanParamMethod.readInstanceField(clientField, - handleBeanParamMethod.getThis())); + handleBeanParamMethod.getThis()), + formParams); handleBeanParamMethod.returnValue(invocationBuilderRef); invocationBuilderEnrichers.put(handleBeanParamDescriptor, paramValue); @@ -1219,12 +1222,13 @@ private void handleSubResourceMethod(List AssignableResultHandle invocationBuilderRef = handleBeanParamMethod .createVariable(Invocation.Builder.class); handleBeanParamMethod.assign(invocationBuilderRef, handleBeanParamMethod.getMethodParam(0)); - addBeanParamData(subMethodCreator, handleBeanParamMethod, + formParams = addBeanParamData(subMethodCreator, handleBeanParamMethod, invocationBuilderRef, beanParam.getItems(), subMethodCreator.getMethodParam(paramIdx), methodTarget, index, subMethodCreator.readInstanceField(clientField, subMethodCreator.getThis()), handleBeanParamMethod.readInstanceField(clientField, - handleBeanParamMethod.getThis())); + handleBeanParamMethod.getThis()), + formParams); handleBeanParamMethod.returnValue(invocationBuilderRef); invocationBuilderEnrichers.put(handleBeanParamDescriptor, @@ -2098,7 +2102,7 @@ private Optional getJavaMethod(ClassInfo interfaceClass, ResourceMet return maybeMethod; } - private void addBeanParamData(BytecodeCreator methodCreator, + private AssignableResultHandle addBeanParamData(MethodCreator methodCreator, BytecodeCreator invocationBuilderEnricher, // Invocation.Builder executePut$$enrichInvocationBuilder${noOfBeanParam}(Invocation.Builder) AssignableResultHandle invocationBuilder, List beanParamItems, @@ -2106,7 +2110,29 @@ private void addBeanParamData(BytecodeCreator methodCreator, AssignableResultHandle target, // can only be used in the current method, not in `invocationBuilderEnricher` IndexView index, ResultHandle client, - ResultHandle invocationEnricherClient) { // this client or containing client if this is a sub-client + ResultHandle invocationEnricherClient, // this client or containing client if this is a sub-client + AssignableResultHandle formParams) { + // Form params collector must be initialized at method root level before any inner blocks that may use it + if (areFormParamsDefinedIn(beanParamItems)) { + formParams = createIfAbsent(methodCreator, formParams); + } + + addSubBeanParamData(methodCreator, invocationBuilderEnricher, invocationBuilder, beanParamItems, param, target, + index, client, invocationEnricherClient, formParams); + + return formParams; + } + + private void addSubBeanParamData(BytecodeCreator methodCreator, + BytecodeCreator invocationBuilderEnricher, // Invocation.Builder executePut$$enrichInvocationBuilder${noOfBeanParam}(Invocation.Builder) + AssignableResultHandle invocationBuilder, + List beanParamItems, + ResultHandle param, + AssignableResultHandle target, // can only be used in the current method, not in `invocationBuilderEnricher` + IndexView index, + ResultHandle client, + ResultHandle invocationEnricherClient, // this client or containing client if this is a sub-client + AssignableResultHandle formParams) { BytecodeCreator creator = methodCreator.ifNotNull(param).trueBranch(); BytecodeCreator invoEnricher = invocationBuilderEnricher.ifNotNull(invocationBuilderEnricher.getMethodParam(1)) .trueBranch(); @@ -2115,8 +2141,8 @@ private void addBeanParamData(BytecodeCreator methodCreator, case BEAN_PARAM: BeanParamItem beanParamItem = (BeanParamItem) item; ResultHandle beanParamElementHandle = beanParamItem.extract(creator, param); - addBeanParamData(creator, invoEnricher, invocationBuilder, beanParamItem.items(), - beanParamElementHandle, target, index, client, invocationEnricherClient); + addSubBeanParamData(creator, invoEnricher, invocationBuilder, beanParamItem.items(), + beanParamElementHandle, target, index, client, invocationEnricherClient, formParams); break; case QUERY_PARAM: QueryParamItem queryParam = (QueryParamItem) item; @@ -2146,12 +2172,33 @@ private void addBeanParamData(BytecodeCreator methodCreator, pathParam.getPathParamName(), pathParam.extract(creator, param), pathParam.getParamType(), client); break; + case FORM_PARAM: + FormParamItem formParam = (FormParamItem) item; + addFormParam(creator, formParam.getFormParamName(), formParam.extract(creator, param), + formParam.getParamType(), client, formParams); + break; default: - throw new IllegalStateException("Unimplemented"); // TODO form params, etc + throw new IllegalStateException("Unimplemented"); } } } + private boolean areFormParamsDefinedIn(List beanParamItems) { + for (Item item : beanParamItems) { + switch (item.type()) { + case FORM_PARAM: + return true; + case BEAN_PARAM: + if (areFormParamsDefinedIn(((BeanParamItem) item).items())) { + return true; + } + break; + } + } + + return false; + } + // takes a result handle to target as one of the parameters, returns a result handle to a modified target private ResultHandle addQueryParam(BytecodeCreator methodCreator, ResultHandle target, @@ -2234,6 +2281,17 @@ private void addPathParam(BytecodeCreator methodCreator, AssignableResultHandle methodCreator.load(paramName), handle)); } + private void addFormParam(BytecodeCreator methodCreator, String paramName, ResultHandle formParamHandle, + String parameterType, + ResultHandle client, AssignableResultHandle formParams) { + ResultHandle convertedHandle = methodCreator.invokeVirtualMethod( + MethodDescriptor.ofMethod(RestClientBase.class, "convertParam", Object.class, Object.class, Class.class), + client, formParamHandle, + methodCreator.loadClass(parameterType)); + methodCreator.invokeInterfaceMethod(MULTIVALUED_MAP_ADD, formParams, + methodCreator.load(paramName), convertedHandle); + } + private void addCookieParam(BytecodeCreator invoBuilderEnricher, AssignableResultHandle invocationBuilder, String paramName, ResultHandle cookieParamHandle, String paramType, ResultHandle client) { cookieParamHandle = invoBuilderEnricher.invokeVirtualMethod( diff --git a/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/beanparam/BeanFormParamTest.java b/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/beanparam/BeanFormParamTest.java new file mode 100644 index 00000000000000..50cd2331dd1cfb --- /dev/null +++ b/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/beanparam/BeanFormParamTest.java @@ -0,0 +1,73 @@ +package io.quarkus.rest.client.reactive.beanparam; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.net.URI; + +import javax.ws.rs.BeanParam; +import javax.ws.rs.Consumes; +import javax.ws.rs.FormParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.core.MediaType; + +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 BeanFormParamTest { + @RegisterExtension + static final QuarkusUnitTest TEST = new QuarkusUnitTest(); + + @TestHTTPResource + URI baseUri; + + @Test + void shouldPassFormParamsFromBeanParam() { + assertThat(clientBuilder().build(FormTestClient.class).postFormParams(new BeanWithFormParams("value1", "value2"))) + .isEqualTo( + "received value1-value2"); + } + + private RestClientBuilder clientBuilder() { + return RestClientBuilder.newBuilder().baseUri(baseUri); + } + + @Path("/form") + public interface FormTestClient { + @POST + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + String postFormParams(@BeanParam BeanWithFormParams beanParam); + } + + public static class BeanWithFormParams { + private final String param1; + private final String param2; + + public BeanWithFormParams(String param1, String param2) { + this.param1 = param1; + this.param2 = param2; + } + + @FormParam("param1") + public String getParam1() { + return param1; + } + + @FormParam("param2") + public String getParam2() { + return param2; + } + } + + @Path("/form") + public static class FormTestResource { + @POST + public String post(@FormParam("param1") String param1, @FormParam("param2") String param2) { + return String.format("received %s-%s", param1, param2); + } + } +} diff --git a/independent-projects/resteasy-reactive/client/processor/pom.xml b/independent-projects/resteasy-reactive/client/processor/pom.xml index 9b0ee6c18fc2f2..e33ad4140828bb 100644 --- a/independent-projects/resteasy-reactive/client/processor/pom.xml +++ b/independent-projects/resteasy-reactive/client/processor/pom.xml @@ -38,23 +38,26 @@ jakarta.enterprise jakarta.enterprise.cdi-api - jakarta.annotation jakarta.annotation-api + + org.jboss.logging + jboss-logging + + org.junit.jupiter junit-jupiter test - - org.jboss.logging - jboss-logging + org.assertj + assertj-core + test - 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 4bc0d551afdcf3..78c5d7d1c76144 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,13 +2,16 @@ 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.FORM_PARAM; import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.HEADER_PARAM; import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.PATH_PARAM; import static org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames.QUERY_PARAM; import java.util.ArrayList; +import java.util.Collections; import java.util.List; -import java.util.Map; +import java.util.function.BiFunction; +import java.util.stream.Collectors; import org.jboss.jandex.AnnotationInstance; import org.jboss.jandex.AnnotationTarget; import org.jboss.jandex.ClassInfo; @@ -29,102 +32,60 @@ public static List parse(ClassInfo beanParamClass, IndexView index) { resultList.addAll(parse(index.getClassByName(beanParamClass.superName()), index)); } - Map> annotations = beanParamClass.annotations(); - List queryParams = annotations.get(QUERY_PARAM); - if (queryParams != null) { - for (AnnotationInstance annotation : queryParams) { - AnnotationTarget target = annotation.target(); - if (target.kind() == AnnotationTarget.Kind.FIELD) { - FieldInfo fieldInfo = target.asField(); - resultList.add(new QueryParamItem(annotation.value().asString(), - new FieldExtractor(null, fieldInfo.name(), fieldInfo.declaringClass().name().toString()), - fieldInfo.type())); - } else if (target.kind() == AnnotationTarget.Kind.METHOD) { - MethodInfo getterMethod = getGetterMethod(beanParamClass, target.asMethod()); - resultList.add(new QueryParamItem(annotation.value().asString(), - new GetterExtractor(getterMethod), getterMethod.returnType())); - } - } - } - List beanParams = annotations.get(BEAN_PARAM); - if (beanParams != null) { - for (AnnotationInstance annotation : beanParams) { - AnnotationTarget target = annotation.target(); - if (target.kind() == AnnotationTarget.Kind.FIELD) { - FieldInfo fieldInfo = target.asField(); + resultList.addAll(paramItemsForFieldsAndMethods(beanParamClass, QUERY_PARAM, + (annotationValue, fieldInfo) -> new QueryParamItem(annotationValue, + new FieldExtractor(null, fieldInfo.name(), fieldInfo.declaringClass().name().toString()), + fieldInfo.type()), + (annotationValue, getterMethod) -> new QueryParamItem(annotationValue, new GetterExtractor(getterMethod), + getterMethod.returnType()))); + + resultList.addAll(paramItemsForFieldsAndMethods(beanParamClass, BEAN_PARAM, + (annotationValue, fieldInfo) -> { Type type = fieldInfo.type(); if (type.kind() == Type.Kind.CLASS) { List subBeanParamItems = parse(index.getClassByName(type.asClassType().name()), index); - resultList.add(new BeanParamItem(subBeanParamItems, - new FieldExtractor(null, fieldInfo.name(), fieldInfo.declaringClass().name().toString()))); + return new BeanParamItem(subBeanParamItems, + new FieldExtractor(null, fieldInfo.name(), fieldInfo.declaringClass().name().toString())); } else { throw new IllegalArgumentException("BeanParam annotation used on a field that is not an object: " + beanParamClass.name() + "." + fieldInfo.name()); } - } else if (target.kind() == AnnotationTarget.Kind.METHOD) { - // this should be getter or setter - MethodInfo methodInfo = target.asMethod(); - MethodInfo getter = getGetterMethod(beanParamClass, methodInfo); - Type returnType = getter.returnType(); + }, + (annotationValue, getterMethod) -> { + Type returnType = getterMethod.returnType(); List items = parse(index.getClassByName(returnType.name()), index); - resultList.add(new BeanParamItem(items, new GetterExtractor(getter))); - } - } - } + return new BeanParamItem(items, new GetterExtractor(getterMethod)); + })); - List cookieParams = annotations.get(COOKIE_PARAM); - if (cookieParams != null) { - for (AnnotationInstance annotation : cookieParams) { - AnnotationTarget target = annotation.target(); - if (target.kind() == AnnotationTarget.Kind.FIELD) { - FieldInfo fieldInfo = target.asField(); - resultList.add(new CookieParamItem(annotation.value().asString(), - new FieldExtractor(null, fieldInfo.name(), - fieldInfo.declaringClass().name().toString()), - fieldInfo.type().name().toString())); - } else if (target.kind() == AnnotationTarget.Kind.METHOD) { - MethodInfo getterMethod = getGetterMethod(beanParamClass, target.asMethod()); - resultList.add(new CookieParamItem(annotation.value().asString(), - new GetterExtractor(getterMethod), getterMethod.returnType().name().toString())); - } - } - } + resultList.addAll(paramItemsForFieldsAndMethods(beanParamClass, COOKIE_PARAM, + (annotationValue, fieldInfo) -> new CookieParamItem(annotationValue, + new FieldExtractor(null, fieldInfo.name(), + fieldInfo.declaringClass().name().toString()), + fieldInfo.type().name().toString()), + (annotationValue, getterMethod) -> new CookieParamItem(annotationValue, + new GetterExtractor(getterMethod), getterMethod.returnType().name().toString()))); - List headerParams = annotations.get(HEADER_PARAM); - if (headerParams != null) { - for (AnnotationInstance headerParamAnnotation : headerParams) { - AnnotationTarget target = headerParamAnnotation.target(); - if (target.kind() == AnnotationTarget.Kind.FIELD) { - FieldInfo fieldInfo = target.asField(); - String paramType = fieldInfo.type().name().toString(); - resultList.add(new HeaderParamItem(headerParamAnnotation.value().asString(), - new FieldExtractor(null, fieldInfo.name(), fieldInfo.declaringClass().name().toString()), - paramType)); - } else if (target.kind() == AnnotationTarget.Kind.METHOD) { - MethodInfo getterMethod = getGetterMethod(beanParamClass, target.asMethod()); - resultList.add(new HeaderParamItem(headerParamAnnotation.value().asString(), - new GetterExtractor(getterMethod), getterMethod.returnType().name().toString())); - } - } - } + resultList.addAll(paramItemsForFieldsAndMethods(beanParamClass, HEADER_PARAM, + (annotationValue, fieldInfo) -> new HeaderParamItem(annotationValue, + new FieldExtractor(null, fieldInfo.name(), fieldInfo.declaringClass().name().toString()), + fieldInfo.type().name().toString()), + (annotationValue, getterMethod) -> new HeaderParamItem(annotationValue, + new GetterExtractor(getterMethod), getterMethod.returnType().name().toString()))); - List pathParams = annotations.get(PATH_PARAM); - if (pathParams != null) { - for (AnnotationInstance pathParamAnnotation : pathParams) { - AnnotationTarget target = pathParamAnnotation.target(); - if (target.kind() == AnnotationTarget.Kind.FIELD) { - FieldInfo fieldInfo = target.asField(); - String fieldType = fieldInfo.type().name().toString(); - resultList.add(new PathParamItem(pathParamAnnotation.value().asString(), fieldType, - new FieldExtractor(null, fieldInfo.name(), fieldInfo.declaringClass().name().toString()))); - } else if (target.kind() == AnnotationTarget.Kind.METHOD) { - MethodInfo getterMethod = getGetterMethod(beanParamClass, target.asMethod()); - String paramType = getterMethod.returnType().name().toString(); - resultList.add(new PathParamItem(pathParamAnnotation.value().asString(), paramType, - new GetterExtractor(getterMethod))); - } - } - } + resultList.addAll(paramItemsForFieldsAndMethods(beanParamClass, PATH_PARAM, + (annotationValue, fieldInfo) -> new PathParamItem(annotationValue, fieldInfo.type().name().toString(), + new FieldExtractor(null, fieldInfo.name(), fieldInfo.declaringClass().name().toString())), + (annotationValue, getterMethod) -> new PathParamItem(annotationValue, + getterMethod.returnType().name().toString(), + new GetterExtractor(getterMethod)))); + + resultList.addAll(paramItemsForFieldsAndMethods(beanParamClass, FORM_PARAM, + (annotationValue, fieldInfo) -> new FormParamItem(annotationValue, + fieldInfo.type().name().toString(), + new FieldExtractor(null, fieldInfo.name(), fieldInfo.declaringClass().name().toString())), + (annotationValue, getterMethod) -> new FormParamItem(annotationValue, + getterMethod.returnType().name().toString(), + new GetterExtractor(getterMethod)))); return resultList; } @@ -148,6 +109,52 @@ private static MethodInfo getGetterMethod(ClassInfo beanParamClass, MethodInfo m return getter; } + private static List paramItemsForFieldsAndMethods(ClassInfo beanParamClass, DotName parameterType, + BiFunction fieldExtractor, BiFunction methodExtractor) { + return ParamTypeAnnotations.of(beanParamClass, parameterType).itemsForFieldsAndMethods(fieldExtractor, methodExtractor); + } + private BeanParamParser() { } + + private static class ParamTypeAnnotations { + private final ClassInfo beanParamClass; + private final List annotations; + + private ParamTypeAnnotations(ClassInfo beanParamClass, DotName parameterType) { + this.beanParamClass = beanParamClass; + + List relevantAnnotations = beanParamClass.annotations().get(parameterType); + this.annotations = relevantAnnotations == null + ? Collections.emptyList() + : relevantAnnotations.stream().filter(this::isFieldOrMethodAnnotation).collect(Collectors.toList()); + } + + private static ParamTypeAnnotations of(ClassInfo beanParamClass, DotName parameterType) { + return new ParamTypeAnnotations(beanParamClass, parameterType); + } + + private List itemsForFieldsAndMethods(BiFunction itemFromFieldExtractor, + BiFunction itemFromMethodExtractor) { + return annotations.stream() + .map(annotation -> toItem(annotation, itemFromFieldExtractor, itemFromMethodExtractor)) + .collect(Collectors.toList()); + } + + private T toItem(AnnotationInstance annotation, + BiFunction itemFromFieldExtractor, + BiFunction itemFromMethodExtractor) { + String annotationValue = annotation.value() == null ? null : annotation.value().asString(); + + return annotation.target().kind() == AnnotationTarget.Kind.FIELD + ? itemFromFieldExtractor.apply(annotationValue, annotation.target().asField()) + : itemFromMethodExtractor.apply(annotationValue, + getGetterMethod(beanParamClass, annotation.target().asMethod())); + } + + private boolean isFieldOrMethodAnnotation(AnnotationInstance annotation) { + return annotation.target().kind() == AnnotationTarget.Kind.FIELD + || annotation.target().kind() == AnnotationTarget.Kind.METHOD; + } + } } 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 new file mode 100644 index 00000000000000..4a138bf61ff742 --- /dev/null +++ b/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/FormParamItem.java @@ -0,0 +1,21 @@ +package org.jboss.resteasy.reactive.client.processor.beanparam; + +public class FormParamItem extends Item { + + private final String formParamName; + private final String paramType; + + public FormParamItem(String formParamName, String paramType, ValueExtractor valueExtractor) { + super(ItemType.FORM_PARAM, valueExtractor); + this.formParamName = formParamName; + this.paramType = paramType; + } + + public String getFormParamName() { + return formParamName; + } + + public String getParamType() { + return paramType; + } +} diff --git a/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/ItemType.java b/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/ItemType.java index c7c5f1d8891f35..7d0b9f8a97ec55 100644 --- a/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/ItemType.java +++ b/independent-projects/resteasy-reactive/client/processor/src/main/java/org/jboss/resteasy/reactive/client/processor/beanparam/ItemType.java @@ -6,5 +6,6 @@ public enum ItemType { COOKIE, HEADER_PARAM, PATH_PARAM, + FORM_PARAM, // TODO: more } diff --git a/independent-projects/resteasy-reactive/client/processor/src/test/java/org/jboss/resteasy/reactive/client/processor/beanparam/BeanParamParserTest.java b/independent-projects/resteasy-reactive/client/processor/src/test/java/org/jboss/resteasy/reactive/client/processor/beanparam/BeanParamParserTest.java new file mode 100644 index 00000000000000..a180369752c059 --- /dev/null +++ b/independent-projects/resteasy-reactive/client/processor/src/test/java/org/jboss/resteasy/reactive/client/processor/beanparam/BeanParamParserTest.java @@ -0,0 +1,85 @@ +package org.jboss.resteasy.reactive.client.processor.beanparam; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.*; + +import java.io.IOException; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; +import java.util.function.Consumer; +import javax.ws.rs.BeanParam; +import javax.ws.rs.CookieParam; +import javax.ws.rs.FormParam; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.PathParam; +import javax.ws.rs.QueryParam; +import org.jboss.jandex.DotName; +import org.jboss.jandex.Index; +import org.junit.jupiter.api.Test; + +/** + * Test for {@link BeanParamParser}. + */ +public class BeanParamParserTest { + + @Test + public void mustRecursivelyParseAllParamTypes() throws IOException { + Index index = Index.of(BeanExample.class, BeanExample.InnerBean.class); + List parseResult = BeanParamParser.parse(index.getClassByName(DotName.createSimple(BeanExample.class.getName())), + index); + assertNotNull(parseResult); + parseResult.sort(Comparator.comparing(Item::type)); + + assertThat(parseResult).hasSize(4); + Iterator itemIterator = parseResult.iterator(); + + assertThatNextItemSatisfies(itemIterator, BeanParamItem.class, item -> { + List beanParamItems = item.items(); + beanParamItems.sort(Comparator.comparing(Item::type)); + assertThat(beanParamItems).hasSize(2); + Iterator subItemIterator = beanParamItems.iterator(); + assertThatNextItemSatisfies(subItemIterator, QueryParamItem.class, + subItem -> assertThat(subItem.name()).isEqualTo("queryParam")); + assertThatNextItemSatisfies(subItemIterator, HeaderParamItem.class, + subItem -> assertThat(subItem.getHeaderName()).isEqualTo("headerParam")); + }); + + assertThatNextItemSatisfies(itemIterator, CookieParamItem.class, + subItem -> assertThat(subItem.getCookieName()).isEqualTo("cookieParam")); + assertThatNextItemSatisfies(itemIterator, PathParamItem.class, + subItem -> assertThat(subItem.getPathParamName()).isEqualTo("pathParam")); + assertThatNextItemSatisfies(itemIterator, FormParamItem.class, + subItem -> assertThat(subItem.getFormParamName()).isEqualTo("formParam")); + } + + @SuppressWarnings("unchecked") + private void assertThatNextItemSatisfies(Iterator itemIterator, Class clazz, + Consumer condition) { + Item nextItem = itemIterator.next(); + assertThat(nextItem).isInstanceOf(clazz); + condition.accept((T) nextItem); + } + + private static class BeanExample { + @FormParam("formParam") + String formParam; + + @CookieParam("cookieParam") + String cookieParam; + + @PathParam("pathParam") + String pathParam; + + @BeanParam + InnerBean innerBean; + + private static class InnerBean { + @QueryParam("queryParam") + String queryParam; + + @HeaderParam("headerParam") + String headerParam; + } + } +}