Skip to content

Commit

Permalink
Merge pull request quarkusio#31931 from Sgitario/31866_new
Browse files Browse the repository at this point in the history
Support of generic collections in RESTEasy Reactive server and client
  • Loading branch information
geoand authored Mar 17, 2023
2 parents 7fe54ed + 41aba27 commit b2ce4c7
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -941,7 +941,7 @@ A more full example of generated client (with sub-resource) can is at the bottom
MethodDescriptor handleHeaderDescriptor = MethodDescriptor.ofMethod(name,
method.getName() + "$$" + methodIndex + "$$handleHeader$$" + paramIdx,
Invocation.Builder.class,
Invocation.Builder.class, param.type);
Invocation.Builder.class, param.declaredType);
MethodCreator handleHeaderMethod = classContext.classCreator.getMethodCreator(
handleHeaderDescriptor).setModifiers(Modifier.PRIVATE);

Expand Down Expand Up @@ -1358,7 +1358,7 @@ private void handleSubResourceMethod(List<JaxrsClientReactiveEnricherBuildItem>
subMethod.getName() + "$$" + subMethodIndex + "$$handleHeader$$param"
+ inheritedParamIndex + "$" + subParamField.paramIndex,
Invocation.Builder.class,
Invocation.Builder.class, param.type);
Invocation.Builder.class, param.declaredType);
MethodCreator handleHeaderMethod = subContext.classCreator.getMethodCreator(
handleHeaderDescriptor).setModifiers(Modifier.PRIVATE);

Expand Down Expand Up @@ -1464,7 +1464,7 @@ private void handleSubResourceMethod(List<JaxrsClientReactiveEnricherBuildItem>
MethodDescriptor handleHeaderDescriptor = MethodDescriptor.ofMethod(subName,
subMethod.getName() + "$$" + subMethodIndex + "$$handleHeader$$" + paramIdx,
Invocation.Builder.class,
Invocation.Builder.class, param.type);
Invocation.Builder.class, param.declaredType);
MethodCreator handleHeaderMethod = subContext.classCreator.getMethodCreator(
handleHeaderDescriptor).setModifiers(Modifier.PRIVATE);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.SortedSet;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.stream.Collectors;

import jakarta.inject.Inject;
import jakarta.json.JsonArray;
Expand Down Expand Up @@ -143,6 +147,42 @@ public Response filters(@Context HttpHeaders headers, @RestHeader("filter-reques
return Response.ok().header("filter-request", header).build();
}

@GET
@Path("header-param-list")
public Object headerParamWithList(@HeaderParam("header") List list) {
return collectionToString(list);
}

@GET
@Path("rest-header-list")
public Object restHeaderWithList(@RestHeader List header) {
return collectionToString(header);
}

@GET
@Path("header-param-set")
public Object headerParamWithSet(@HeaderParam("header") Set list) {
return collectionToString(list);
}

@GET
@Path("rest-header-set")
public Object restHeaderWithSet(@RestHeader Set header) {
return collectionToString(header);
}

@GET
@Path("header-param-sorted-set")
public Object headerParamWithSortedSet(@HeaderParam("header") SortedSet list) {
return collectionToString(list);
}

@GET
@Path("rest-header-sorted-set")
public String restHeaderWithSortedSet(@RestHeader SortedSet header) {
return collectionToString(header);
}

@GET
@Path("feature-filters")
public Response featureFilters(@Context HttpHeaders headers) {
Expand Down Expand Up @@ -380,4 +420,8 @@ public String simplifiedResourceInfo(@Context SimpleResourceInfo simplifiedResou
public String bigDecimalConverter(BigDecimal val) {
return val.toString();
}

private String collectionToString(Collection list) {
return (String) list.stream().map(Object::toString).collect(Collectors.joining(", "));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
import org.junit.jupiter.api.condition.DisabledOnOs;
import org.junit.jupiter.api.condition.OS;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

import io.quarkus.test.QuarkusUnitTest;
import io.restassured.RestAssured;
Expand Down Expand Up @@ -313,6 +315,34 @@ public void testHeaderParamInCtor() {
.then().body(Matchers.is(emptyString()));
}

@ParameterizedTest
@ValueSource(strings = {
"rest-header-list",
"rest-header-set",
"rest-header-sorted-set"
})
public void testRestHeaderUsingCollection(String path) {
RestAssured.with().header("header", "a", "b")
.get("/simple/" + path)
.then()
.statusCode(HttpStatus.SC_OK)
.body(Matchers.equalTo("a, b"));
}

@ParameterizedTest
@ValueSource(strings = {
"header-param-list",
"header-param-set",
"header-param-sorted-set"
})
public void testHeaderParamUsingCollection(String path) {
RestAssured.with().header("header", "a", "b")
.get("/simple/" + path)
.then()
.statusCode(HttpStatus.SC_OK)
.body(Matchers.equalTo("a, b"));
}

@Test
public void testFormMap() {
RestAssured
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@
import static org.assertj.core.api.Assertions.assertThat;

import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.stream.Collectors;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.ws.rs.GET;
Expand Down Expand Up @@ -40,6 +47,15 @@ void testNullHeaders() {
assertThat(client.cookieSub("bar", null).send(null, "bar4", "dummy")).isEqualTo("bar:null:null:bar4:X-My-Header/dummy");
}

@Test
void testHeadersWithCollections() {
String expected = "a, b, c, d";
Client client = RestClientBuilder.newBuilder().baseUri(baseUri).build(Client.class);
assertThat(client.headersList(List.of("a", "b"), List.of("c", "d"))).isEqualTo(expected);
assertThat(client.headersSet(Set.of("a", "b"), Set.of("c", "d"))).isEqualTo(expected);
assertThat(client.headersSet(new TreeSet(List.of("a", "b")), new TreeSet(List.of("c", "d")))).isEqualTo(expected);
}

@Path("/")
@ApplicationScoped
public static class Resource {
Expand All @@ -51,12 +67,50 @@ public String returnHeaders(@HeaderParam("foo") String header, @HeaderParam("foo
return header + ":" + header2 + ":" + header3 + ":" + header4 + ":" + myHeaderName + "/"
+ headers.getHeaderString("X-My-Header");
}

@GET
@Path("/headers-list")
public String headersList(@HeaderParam("foo") List foo, @RestHeader List header) {
return joiningCollections(foo, header);
}

@GET
@Path("/headers-set")
public String headersSet(@HeaderParam("foo") Set foo, @RestHeader Set header) {
return joiningCollections(foo, header);
}

@GET
@Path("/headers-sorted-set")
public String headersSortedSet(@HeaderParam("foo") SortedSet foo, @RestHeader SortedSet header) {
return joiningCollections(foo, header);
}

private String joiningCollections(Collection... collections) {
List<String> allHeaders = new ArrayList<>();
for (Collection collection : collections) {
collection.forEach(v -> allHeaders.add((String) v));
}
return allHeaders.stream().collect(Collectors.joining(", "));
}
}

public interface Client {

@Path("/")
SubClient cookieSub(@HeaderParam("foo") String cookie, @HeaderParam("foo2") String cookie2);

@GET
@Path("/headers-list")
String headersList(@HeaderParam("foo") List foo, @RestHeader List header);

@GET
@Path("/headers-set")
String headersSet(@HeaderParam("foo") Set foo, @RestHeader Set header);

@GET
@Path("/headers-sorted-set")
String headersSortedSet(@HeaderParam("foo") SortedSet foo, @RestHeader SortedSet header);
}

public interface SubClient {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.quarkus.rest.client.reactive.runtime;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

Expand Down Expand Up @@ -81,11 +82,13 @@ public void filter(ResteasyReactiveClientRequestContext requestContext) {
}
}

private static List<String> castToListOfStrings(List<Object> values) {
private static List<String> castToListOfStrings(Collection<Object> values) {
List<String> result = new ArrayList<>();
for (Object value : values) {
if (value instanceof String) {
result.add((String) value);
} else if (value instanceof Collection) {
result.addAll(castToListOfStrings((Collection<Object>) value));
} else {
result.add(String.valueOf(value));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1359,13 +1359,28 @@ && isParameterContainerType(paramType.asClassType())) {
elementType = paramType.name().toString();
handleTemporalParam(builder, paramType.name(), anns, currentMethodInfo);
typeHandled = true;
} else if (paramType.name().equals(LIST) && (type == ParameterType.QUERY)) { // RESTEasy Classic handles the non-generic List type
} else if (paramType.name().equals(LIST) && (type == ParameterType.QUERY
|| type == ParameterType.HEADER)) { // RESTEasy Classic handles the non-generic List type
elementType = String.class.getName();
typeHandled = true;
builder.setSingle(false);
if (convertible) {
handleListParam(existingConverters, errorLocation, hasRuntimeConverters, builder, elementType);
}
} else if (paramType.name().equals(SET) && type == ParameterType.HEADER) { // RESTEasy Classic handles the non-generic Set type
elementType = String.class.getName();
typeHandled = true;
builder.setSingle(false);
if (convertible) {
handleSetParam(existingConverters, errorLocation, hasRuntimeConverters, builder, elementType);
}
} else if (paramType.name().equals(SORTED_SET) && type == ParameterType.HEADER) { // RESTEasy Classic handles the non-generic SortedSet type
elementType = String.class.getName();
typeHandled = true;
builder.setSingle(false);
if (convertible) {
handleSortedSetParam(existingConverters, errorLocation, hasRuntimeConverters, builder, elementType);
}
} else if (paramType.kind() == Kind.ARRAY) {
ArrayType at = paramType.asArrayType();
typeHandled = true;
Expand Down

0 comments on commit b2ce4c7

Please sign in to comment.