Skip to content

Commit

Permalink
Add @ClientQueryParam to Reactive REST Client
Browse files Browse the repository at this point in the history
This is analogous to what MP REST Client provides
in @ClientHeaderParam

Resolves: #21443
  • Loading branch information
geoand committed Nov 15, 2022
1 parent 839a619 commit 16888b0
Show file tree
Hide file tree
Showing 12 changed files with 655 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,20 @@ public interface JaxrsClientReactiveEnricher {
void forClass(MethodCreator ctor, AssignableResultHandle globalTarget,
ClassInfo interfaceClass, IndexView index);

/**
* Called when a {@link javax.ws.rs.client.WebTarget} has been populated for a normal Client
*/
void forWebTarget(MethodCreator methodCreator, IndexView index, ClassInfo interfaceClass, MethodInfo method,
AssignableResultHandle webTarget, BuildProducer<GeneratedClassBuildItem> generatedClasses);

/**
* Called when a {@link javax.ws.rs.client.WebTarget} has been populated for a sub Client
*/
void forSubResourceWebTarget(MethodCreator methodCreator, IndexView index, ClassInfo rootInterfaceClass,
ClassInfo subInterfaceClass,
MethodInfo rootMethod, MethodInfo subMethod, AssignableResultHandle webTarget,
BuildProducer<GeneratedClassBuildItem> generatedClasses);

/**
* Method-level alterations
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -964,6 +964,12 @@ A more full example of generated client (with sub-resource) can is at the bottom
}
}

for (JaxrsClientReactiveEnricherBuildItem enricher : enrichers) {
enricher.getEnricher()
.forWebTarget(methodCreator, index, interfaceClass, jandexMethod, methodTarget,
generatedClasses);
}

AssignableResultHandle builder = methodCreator.createVariable(Invocation.Builder.class);
if (method.getProduces() == null || method.getProduces().length == 0) { // this should never happen!
methodCreator.assign(builder, methodCreator.invokeInterfaceMethod(
Expand Down Expand Up @@ -1457,6 +1463,12 @@ private void handleSubResourceMethod(List<JaxrsClientReactiveEnricherBuildItem>
// if the response is multipart, let's add it's class to the appropriate collection:
addResponseTypeIfMultipart(multipartResponseTypes, jandexSubMethod, index);

for (JaxrsClientReactiveEnricherBuildItem enricher : enrichers) {
enricher.getEnricher()
.forSubResourceWebTarget(subMethodCreator, index, interfaceClass, subInterface,
jandexMethod, jandexSubMethod, methodTarget, generatedClasses);
}

AssignableResultHandle builder = subMethodCreator.createVariable(Invocation.Builder.class);
if (method.getProduces() == null || method.getProduces().length == 0) { // this should never happen!
subMethodCreator.assign(builder, subMethodCreator.invokeInterfaceMethod(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,18 @@
import org.jboss.jandex.DotName;

import io.quarkus.rest.client.reactive.ClientExceptionMapper;
import io.quarkus.rest.client.reactive.ClientQueryParam;
import io.quarkus.rest.client.reactive.ClientQueryParams;

public class DotNames {

public static final DotName REGISTER_PROVIDER = DotName.createSimple(RegisterProvider.class.getName());
public static final DotName REGISTER_PROVIDERS = DotName.createSimple(RegisterProviders.class.getName());
public static final DotName CLIENT_HEADER_PARAM = DotName.createSimple(ClientHeaderParam.class.getName());
public static final DotName CLIENT_HEADER_PARAMS = DotName.createSimple(ClientHeaderParams.class.getName());

public static final DotName CLIENT_QUERY_PARAM = DotName.createSimple(ClientQueryParam.class.getName());
public static final DotName CLIENT_QUERY_PARAMS = DotName.createSimple(ClientQueryParams.class.getName());
public static final DotName REGISTER_CLIENT_HEADERS = DotName.createSimple(RegisterClientHeaders.class.getName());
public static final DotName CLIENT_REQUEST_FILTER = DotName.createSimple(ClientRequestFilter.class.getName());
public static final DotName CLIENT_RESPONSE_FILTER = DotName.createSimple(ClientResponseFilter.class.getName());
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import static io.quarkus.rest.client.reactive.deployment.DotNames.CLIENT_EXCEPTION_MAPPER;
import static io.quarkus.rest.client.reactive.deployment.DotNames.CLIENT_HEADER_PARAM;
import static io.quarkus.rest.client.reactive.deployment.DotNames.CLIENT_HEADER_PARAMS;
import static io.quarkus.rest.client.reactive.deployment.DotNames.CLIENT_QUERY_PARAM;
import static io.quarkus.rest.client.reactive.deployment.DotNames.CLIENT_QUERY_PARAMS;
import static io.quarkus.rest.client.reactive.deployment.DotNames.REGISTER_CLIENT_HEADERS;
import static io.quarkus.rest.client.reactive.deployment.DotNames.REGISTER_PROVIDER;
import static io.quarkus.rest.client.reactive.deployment.DotNames.REGISTER_PROVIDERS;
Expand Down Expand Up @@ -106,6 +108,8 @@ class RestClientReactiveProcessor {
REGISTER_PROVIDERS,
CLIENT_HEADER_PARAM,
CLIENT_HEADER_PARAMS,
CLIENT_QUERY_PARAM,
CLIENT_QUERY_PARAMS,
REGISTER_CLIENT_HEADERS);

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

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

import java.net.URI;
import java.util.List;

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

import org.eclipse.microprofile.rest.client.RestClientBuilder;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import io.quarkus.rest.client.reactive.ClientQueryParam;
import io.quarkus.test.QuarkusUnitTest;
import io.quarkus.test.common.http.TestHTTPResource;

public class ClientQueryParamFromMethodTest {

@TestHTTPResource
URI baseUri;

@RegisterExtension
static final QuarkusUnitTest config = new QuarkusUnitTest()
.withApplicationRoot((jar) -> jar.addClasses(Client.class, SubClient.class, Resource.class, ComputedParam.class));

@Test
void shouldUseValuesOnlyFromClass() {
Client client = RestClientBuilder.newBuilder().baseUri(baseUri)
.build(Client.class);

assertThat(client.setFromClass()).isEqualTo("1/");
}

@Test
void shouldUseValuesFromClassAndMethod() {
Client client = RestClientBuilder.newBuilder().baseUri(baseUri)
.build(Client.class);

assertThat(client.setFromMethodAndClass()).isEqualTo("1/2");
}

@Test
void shouldUseValuesFromMethodWithParam() {
Client client = RestClientBuilder.newBuilder().baseUri(baseUri)
.build(Client.class);

assertThat(client.setFromMethodWithParam()).isEqualTo("-11/-2");
}

@Test
void shouldUseValuesFromQueryParam() {
Client client = RestClientBuilder.newBuilder().baseUri(baseUri)
.build(Client.class);

assertThat(client.setFromQueryParam("111")).isEqualTo("111/2");
}

@Test
void shouldUseValuesFromQueryParams() {
Client client = RestClientBuilder.newBuilder().baseUri(baseUri)
.build(Client.class);

assertThat(client.setFromQueryParams("111", "222")).isEqualTo("111/222");
}

@Test
void shouldUseValuesFromSubclientAnnotations() {
Client client = RestClientBuilder.newBuilder().baseUri(baseUri)
.build(Client.class);

assertThat(client.sub().sub("22")).isEqualTo("11/22");
}

@Path("/")
@ApplicationScoped
public static class Resource {
@GET
public String returnQueryParamValues(@QueryParam("first") List<String> first,
@QueryParam("second") List<String> second) {
return String.join(",", first) + "/" + String.join(",", second);
}
}

@ClientQueryParam(name = "first", value = "{first}")
public interface Client {
@GET
String setFromClass();

@GET
@ClientQueryParam(name = "second", value = "{second}")
String setFromMethodAndClass();

@GET
@ClientQueryParam(name = "second", value = "{second}")
String setFromQueryParam(@QueryParam("first") String first);

@GET
@ClientQueryParam(name = "second", value = "{second}")
String setFromQueryParams(@QueryParam("first") String first, @QueryParam("second") String second);

@GET
@ClientQueryParam(name = "first", value = "{io.quarkus.rest.client.reactive.queries.ComputedParam.withParam}")
@ClientQueryParam(name = "second", value = "{withParam}")
String setFromMethodWithParam();

@Path("")
SubClient sub();

default String first() {
return "1";
}

default String second() {
return "2";
}

default String withParam(String name) {
if ("first".equals(name)) {
return "-1";
} else if ("second".equals(name)) {
return "-2";
}
throw new IllegalArgumentException();
}
}

@ClientQueryParam(name = "first", value = "{first}")
public interface SubClient {

@GET
String sub(@QueryParam("second") String second);

default String first() {
return "11";
}
}

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

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

import java.net.URI;

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

import org.eclipse.microprofile.rest.client.RestClientBuilder;
import org.jboss.shrinkwrap.api.asset.StringAsset;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import io.quarkus.rest.client.reactive.ClientQueryParam;
import io.quarkus.test.QuarkusUnitTest;
import io.quarkus.test.common.http.TestHTTPResource;

public class ClientQueryParamFromPropertyTest {
private static final String QUERY_VALUE = "foo";

@TestHTTPResource
URI baseUri;

@RegisterExtension
static final QuarkusUnitTest config = new QuarkusUnitTest()
.withApplicationRoot((jar) -> jar.addClasses(Client.class, Resource.class)
.addAsResource(
new StringAsset("my.property-value=" + QUERY_VALUE),
"application.properties"));

@Test
void shouldSetFromProperties() {
Client client = RestClientBuilder.newBuilder().baseUri(baseUri)
.build(Client.class);

assertThat(client.getWithParam()).isEqualTo(QUERY_VALUE);
}

@Test
void shouldFailOnMissingRequiredProperty() {
Client client = RestClientBuilder.newBuilder().baseUri(baseUri)
.build(Client.class);

assertThatThrownBy(client::missingRequiredProperty)
.isInstanceOf(IllegalArgumentException.class);
}

@Test
void shouldSucceedOnMissingNonRequiredProperty() {
Client client = RestClientBuilder.newBuilder().baseUri(baseUri)
.build(Client.class);

assertThat(client.missingNonRequiredProperty()).isEqualTo(QUERY_VALUE);
}

@Test
void shouldSucceedOnMissingNonRequiredPropertyAndUseOverriddenValue() {
Client client = RestClientBuilder.newBuilder().baseUri(baseUri)
.build(Client.class);

assertThat(client.missingNonRequiredPropertyAndOverriddenValue()).isEqualTo("other");
}

@Path("/")
@ApplicationScoped
public static class Resource {
@GET
public String returnQueryParamValue(@QueryParam("my-param") String param) {
return param;
}
}

@ClientQueryParam(name = "my-param", value = "${my.property-value}")
public interface Client {
@GET
String getWithParam();

@GET
@ClientQueryParam(name = "some-other-param", value = "${non-existent-property}")
String missingRequiredProperty();

@GET
@ClientQueryParam(name = "some-other-param", value = "${non-existent-property}", required = false)
String missingNonRequiredProperty();

@GET
@ClientQueryParam(name = "some-other-param", value = "${non-existent-property}", required = false)
@ClientQueryParam(name = "my-param", value = "other")
String missingNonRequiredPropertyAndOverriddenValue();
}

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

public class ComputedParam {

public static String withParam(String name) {
if ("first".equals(name)) {
return "-11";
} else if ("second".equals(name)) {
return "-22";
}
throw new IllegalArgumentException();
}
}
Loading

0 comments on commit 16888b0

Please sign in to comment.