Skip to content

Commit

Permalink
Fix null query parameter handling in generated RestEasy Reactive clients
Browse files Browse the repository at this point in the history
Also adds missing query handling tests.
  • Loading branch information
kdubb committed May 31, 2022
1 parent a586e0a commit 46b91cb
Show file tree
Hide file tree
Showing 2 changed files with 182 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2325,20 +2325,22 @@ private ResultHandle addQueryParam(MethodInfo jandexMethod, BytecodeCreator meth
AssignableResultHandle result = methodCreator.createVariable(WebTarget.class);
BranchResult isValueNull = methodCreator.ifNull(webTarget);
BytecodeCreator notNullValue = isValueNull.falseBranch();
BranchResult isParamNull = notNullValue.ifNull(queryParamHandle);
BytecodeCreator notNullParam = isParamNull.falseBranch();
if (isMap(type, index)) {
var resolvesTypes = resolveMapTypes(type, index, jandexMethod);
var keyType = resolvesTypes.getKey();
if (!ResteasyReactiveDotNames.STRING.equals(keyType.name())) {
throw new IllegalArgumentException(
"Map parameter types must have String keys. Offending method is: " + jandexMethod);
}
notNullValue.assign(result, webTarget);
notNullParam.assign(result, webTarget);
// Loop through the keys
ResultHandle keySet = notNullValue.invokeInterfaceMethod(ofMethod(Map.class, "keySet", Set.class),
ResultHandle keySet = notNullParam.invokeInterfaceMethod(ofMethod(Map.class, "keySet", Set.class),
queryParamHandle);
ResultHandle keysIterator = notNullValue.invokeInterfaceMethod(
ResultHandle keysIterator = notNullParam.invokeInterfaceMethod(
ofMethod(Set.class, "iterator", Iterator.class), keySet);
BytecodeCreator loopCreator = notNullValue.whileLoop(c -> iteratorHasNext(c, keysIterator)).block();
BytecodeCreator loopCreator = notNullParam.whileLoop(c -> iteratorHasNext(c, keysIterator)).block();
ResultHandle key = loopCreator.invokeInterfaceMethod(
ofMethod(Iterator.class, "next", Object.class), keysIterator);
// get the value and convert
Expand Down Expand Up @@ -2373,7 +2375,7 @@ private ResultHandle addQueryParam(MethodInfo jandexMethod, BytecodeCreator meth
String componentType = null;
if (type.kind() == Type.Kind.ARRAY) {
componentType = type.asArrayType().component().name().toString();
paramArray = notNullValue.checkCast(queryParamHandle, Object[].class);
paramArray = notNullParam.checkCast(queryParamHandle, Object[].class);
} else if (isCollection(type, index)) {
if (type.kind() == PARAMETERIZED_TYPE) {
Type paramType = type.asParameterizedType().arguments().get(0);
Expand All @@ -2384,21 +2386,24 @@ private ResultHandle addQueryParam(MethodInfo jandexMethod, BytecodeCreator meth
if (componentType == null) {
componentType = DotNames.OBJECT.toString();
}
paramArray = notNullValue.invokeStaticMethod(
paramArray = notNullParam.invokeStaticMethod(
MethodDescriptor.ofMethod(ToObjectArray.class, "collection", Object[].class, Collection.class),
queryParamHandle);
} else {
componentType = type.name().toString();
paramArray = notNullValue.invokeStaticMethod(
paramArray = notNullParam.invokeStaticMethod(
MethodDescriptor.ofMethod(ToObjectArray.class, "value", Object[].class, Object.class),
queryParamHandle);
}

addQueryParamToWebTarget(notNullValue, notNullValue.load(paramName), webTarget, client, genericType,
addQueryParamToWebTarget(notNullParam, notNullParam.load(paramName), webTarget, client, genericType,
paramAnnotations, paramIndex,
paramArray, componentType, result);
}

BytecodeCreator nullParam = isParamNull.trueBranch();
nullParam.assign(result, webTarget);

BytecodeCreator nullValue = isValueNull.trueBranch();
nullValue.assign(result, nullValue.loadNull());

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
package io.quarkus.rest.client.reactive.queries;

import static org.assertj.core.api.Assertions.assertThat;

import java.net.URI;
import java.util.AbstractMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import javax.enterprise.context.ApplicationScoped;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.UriInfo;

import org.eclipse.microprofile.rest.client.RestClientBuilder;
import org.jboss.resteasy.reactive.RestQuery;
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 QueryTest {
@RegisterExtension
static final QuarkusUnitTest config = new QuarkusUnitTest()
.withApplicationRoot((jar) -> jar.addClasses(Resource.class));

@TestHTTPResource
URI baseUri;

@Test
void testQuery() {
Client client = RestClientBuilder.newBuilder().baseUri(baseUri).build(Client.class);
assertThat(client.sendQuery("bar")).isEqualTo("bar");
}

@Test
void testNullQuery() {
Client client = RestClientBuilder.newBuilder().baseUri(baseUri).build(Client.class);
assertThat(client.sendQuery(null)).isNull();
}

@Test
void testQueryMap() {
Client client = RestClientBuilder.newBuilder().baseUri(baseUri).build(Client.class);
assertThat(client.sendQueryMap(Map.of("a", "1", "b", "2"))).isEqualTo("a=1,b=2");
}

@Test
void testNullQueryMap() {
Client client = RestClientBuilder.newBuilder().baseUri(baseUri).build(Client.class);
assertThat(client.sendQueryMap(null)).isEqualTo("none");
}

@Test
void testQueryCollection() {
Client client = RestClientBuilder.newBuilder().baseUri(baseUri).build(Client.class);
assertThat(client.sendQueryCollection(List.of("a", "b"))).isEqualTo("a,b");
}

@Test
void testNullQueryCollection() {
Client client = RestClientBuilder.newBuilder().baseUri(baseUri).build(Client.class);
assertThat(client.sendQueryCollection(null)).isEqualTo("none");
}

@Test
void testQueryArray() {
Client client = RestClientBuilder.newBuilder().baseUri(baseUri).build(Client.class);
assertThat(client.sendQueryArray(new String[] { "a", "b" })).isEqualTo("a,b");
}

@Test
void testNullQueryArray() {
Client client = RestClientBuilder.newBuilder().baseUri(baseUri).build(Client.class);
assertThat(client.sendQueryArray(null)).isEqualTo("none");
}

@Test
void testQueriesWithSubresource() {
Client client = RestClientBuilder.newBuilder().baseUri(baseUri).build(Client.class);
assertThat(client.querySub("bar", "bar2").send("bar3", "bar4")).isEqualTo("bar:bar2:bar3:bar4");
}

@Test
void testNullQueriesWithSubresource() {
Client client = RestClientBuilder.newBuilder().baseUri(baseUri).build(Client.class);
assertThat(client.querySub("bar", null).send(null, "bar4")).isEqualTo("bar:null:null:bar4");
}

@Path("/")
@ApplicationScoped
public static class Resource {
@GET
public String returnQueryValue(@QueryParam("foo") String query) {
return query;
}

@Path("map")
@GET
public String returnQueryMap(@Context UriInfo uriInfo) {
if (uriInfo.getQueryParameters().isEmpty()) {
return "none";
}
return uriInfo.getQueryParameters().entrySet().stream()
.flatMap(entry -> entry.getValue().stream()
.map(value -> new AbstractMap.SimpleEntry(entry.getKey(), value)))
.map(entry -> String.format("%s=%s", entry.getKey(), entry.getValue()))
.sorted()
.collect(Collectors.joining(","));
}

@Path("collection")
@GET
public String returnQueryCollection(@QueryParam("foo") List<String> query) {
if (query.isEmpty()) {
return "none";
}
return String.join(",", query);
}

@Path("array")
@GET
public String returnQueryArray(@QueryParam("foo") String[] query) {
if (query.length == 0) {
return "none";
}
return String.join(",", query);
}

@Path("2")
@GET
public String returnQueryValue2(@QueryParam("foo") String query, @QueryParam("foo2") String query2,
@QueryParam("foo3") String query3, @QueryParam("foo4") String query4) {
return query + ":" + query2 + ":" + query3 + ":" + query4;
}
}

public interface Client {

@GET
String sendQuery(@QueryParam("foo") String query);

@Path("map")
@GET
String sendQueryMap(@RestQuery Map<String, String> query);

@Path("collection")
@GET
String sendQueryCollection(@QueryParam("foo") List<String> query);

@Path("array")
@GET
String sendQueryArray(@QueryParam("foo") String[] query);

@Path("2")
SubClient querySub(@QueryParam("foo") String query, @QueryParam("foo2") String query2);
}

public interface SubClient {

@GET
String send(@QueryParam("foo3") String query3, @QueryParam("foo4") String query4);
}

}

0 comments on commit 46b91cb

Please sign in to comment.