-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #22396 from michalszynkiewicz/rcr-param-converters
REST Client Reactive - param converter support
- Loading branch information
Showing
12 changed files
with
502 additions
and
77 deletions.
There are no files selected for viewing
174 changes: 120 additions & 54 deletions
174
...c/main/java/io/quarkus/jaxrs/client/reactive/deployment/JaxrsClientReactiveProcessor.java
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
71 changes: 71 additions & 0 deletions
71
...active/runtime/src/main/java/io/quarkus/jaxrs/client/reactive/runtime/RestClientBase.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
package io.quarkus.jaxrs.client.reactive.runtime; | ||
|
||
import java.io.Closeable; | ||
import java.lang.annotation.Annotation; | ||
import java.lang.reflect.Type; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.concurrent.ConcurrentHashMap; | ||
|
||
import javax.ws.rs.ext.ParamConverter; | ||
import javax.ws.rs.ext.ParamConverterProvider; | ||
|
||
public abstract class RestClientBase implements Closeable { | ||
private final List<ParamConverterProvider> paramConverterProviders; | ||
private final Map<Class<?>, ParamConverterProvider> providerForClass = new ConcurrentHashMap<>(); | ||
|
||
public RestClientBase(List<ParamConverterProvider> providers) { | ||
this.paramConverterProviders = providers; | ||
} | ||
|
||
@SuppressWarnings("unused") // used by generated code | ||
public <T> Object[] convertParamArray(T[] value, Class<T> type) { | ||
ParamConverter<T> converter = getConverter(type, null, null); | ||
|
||
if (converter == null) { | ||
return value; | ||
} else { | ||
Object[] result = new Object[value.length]; | ||
|
||
for (int i = 0; i < value.length; i++) { | ||
result[i] = converter.toString(value[i]); | ||
} | ||
return result; | ||
} | ||
} | ||
|
||
@SuppressWarnings("unused") // used by generated code | ||
public <T> Object convertParam(T value, Class<T> type) { | ||
ParamConverter<T> converter = getConverter(type, null, null); | ||
if (converter != null) { | ||
return converter.toString(value); | ||
} else { | ||
return value; | ||
} | ||
} | ||
|
||
private <T> ParamConverter<T> getConverter(Class<T> type, Type genericType, Annotation[] annotations) { | ||
ParamConverterProvider converterProvider = providerForClass.get(type); | ||
|
||
if (converterProvider == null) { | ||
for (ParamConverterProvider provider : paramConverterProviders) { | ||
ParamConverter<T> converter = provider.getConverter(type, null, null); | ||
if (converter != null) { | ||
providerForClass.put(type, provider); | ||
return converter; | ||
} | ||
} | ||
providerForClass.put(type, NO_PROVIDER); | ||
} else if (converterProvider != NO_PROVIDER) { | ||
return converterProvider.getConverter(type, null, null); | ||
} | ||
return null; | ||
} | ||
|
||
private static final ParamConverterProvider NO_PROVIDER = new ParamConverterProvider() { | ||
@Override | ||
public <T> ParamConverter<T> getConverter(Class<T> rawType, Type genericType, Annotation[] annotations) { | ||
return null; | ||
} | ||
}; | ||
} |
242 changes: 242 additions & 0 deletions
242
...t/src/test/java/io/quarkus/rest/client/reactive/converter/ParamConverterProviderTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,242 @@ | ||
package io.quarkus.rest.client.reactive.converter; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
|
||
import java.lang.annotation.Annotation; | ||
import java.lang.reflect.Type; | ||
import java.net.URI; | ||
|
||
import javax.ws.rs.BeanParam; | ||
import javax.ws.rs.CookieParam; | ||
import javax.ws.rs.GET; | ||
import javax.ws.rs.HeaderParam; | ||
import javax.ws.rs.Path; | ||
import javax.ws.rs.PathParam; | ||
import javax.ws.rs.QueryParam; | ||
import javax.ws.rs.ext.ParamConverterProvider; | ||
|
||
import org.eclipse.microprofile.rest.client.RestClientBuilder; | ||
import org.eclipse.microprofile.rest.client.annotation.RegisterProvider; | ||
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 ParamConverterProviderTest { | ||
@RegisterExtension | ||
static final QuarkusUnitTest TEST = new QuarkusUnitTest(); | ||
|
||
@TestHTTPResource | ||
URI baseUri; | ||
|
||
@Test | ||
void shouldConvertPathParam() { | ||
Client client = RestClientBuilder.newBuilder().baseUri(baseUri) | ||
.build(Client.class); | ||
assertThat(client.get(Param.FIRST)).isEqualTo("1"); | ||
assertThat(client.sub().get(Param.SECOND)).isEqualTo("2"); | ||
|
||
Bean bean = new Bean(); | ||
bean.param = Param.FIRST; | ||
assertThat(client.get(bean)).isEqualTo("1"); | ||
} | ||
|
||
@Test | ||
void shouldConvertQueryParams() { | ||
Client client = RestClientBuilder.newBuilder().baseUri(baseUri) | ||
.build(Client.class); | ||
assertThat(client.getWithQuery(Param.FIRST)).isEqualTo("1"); | ||
assertThat(client.sub().getWithQuery(Param.SECOND)).isEqualTo("2"); | ||
|
||
Bean bean = new Bean(); | ||
bean.param = Param.SECOND; | ||
bean.queryParam = Param.FIRST; | ||
assertThat(client.getWithQuery(bean)).isEqualTo("1"); | ||
} | ||
|
||
@Test | ||
void shouldConvertHeaderParams() { | ||
Client client = RestClientBuilder.newBuilder().baseUri(baseUri) | ||
.build(Client.class); | ||
assertThat(client.getWithHeader(Param.FIRST)).isEqualTo("1"); | ||
assertThat(client.sub().getWithHeader(Param.SECOND)).isEqualTo("2"); | ||
|
||
Bean bean = new Bean(); | ||
bean.param = Param.SECOND; | ||
bean.queryParam = Param.SECOND; | ||
bean.headerParam = Param.FIRST; | ||
assertThat(client.getWithHeader(bean)).isEqualTo("1"); | ||
} | ||
|
||
@Test | ||
void shouldConvertCookieParams() { | ||
Client client = RestClientBuilder.newBuilder().baseUri(baseUri) | ||
.build(Client.class); | ||
assertThat(client.getWithHeader(Param.FIRST)).isEqualTo("1"); | ||
assertThat(client.sub().getWithCookie(Param.SECOND)).isEqualTo("2"); | ||
|
||
Bean bean = new Bean(); | ||
bean.param = Param.SECOND; | ||
bean.queryParam = Param.SECOND; | ||
bean.headerParam = Param.SECOND; | ||
bean.cookieParam = Param.FIRST; | ||
assertThat(client.getWithCookie(bean)).isEqualTo("1"); | ||
} | ||
|
||
@Path("/echo") | ||
@RegisterProvider(ParamConverter.class) | ||
interface Client { | ||
@Path("/sub") | ||
SubClient sub(); | ||
|
||
@GET | ||
@Path("/param/{param}") | ||
String get(@PathParam("param") Param param); | ||
|
||
@GET | ||
@Path("/param/{param}") | ||
String get(@BeanParam Bean beanParam); | ||
|
||
@GET | ||
@Path("/query") | ||
String getWithQuery(@QueryParam("param") Param param); | ||
|
||
@GET | ||
@Path("/query") | ||
String getWithQuery(@BeanParam Bean beanParam); | ||
|
||
@GET | ||
@Path("/header") | ||
String getWithHeader(@HeaderParam("param") Param param); | ||
|
||
@GET | ||
@Path("/header") | ||
String getWithHeader(@BeanParam Bean beanParam); | ||
|
||
@GET | ||
@Path("/cookie") | ||
String getWithCookie(@HeaderParam("cookie-param") Param param); | ||
|
||
@GET | ||
@Path("/cookie") | ||
String getWithCookie(@BeanParam Bean beanParam); | ||
} | ||
|
||
interface SubClient { | ||
@GET | ||
@Path("/param/{param}") | ||
String get(@PathParam("param") Param param); | ||
|
||
@GET | ||
@Path("/query") | ||
String getWithQuery(@QueryParam("param") Param param); | ||
|
||
@GET | ||
@Path("/header") | ||
String getWithHeader(@HeaderParam("param") Param param); | ||
|
||
@GET | ||
@Path("cookie") | ||
String getWithCookie(@CookieParam("cookie-param") Param param); | ||
} | ||
|
||
public static class Bean { | ||
@PathParam("param") | ||
public Param param; | ||
@QueryParam("param") | ||
public Param queryParam; | ||
@HeaderParam("param") | ||
public Param headerParam; | ||
@CookieParam("cookie-param") | ||
public Param cookieParam; | ||
} | ||
|
||
enum Param { | ||
FIRST, | ||
SECOND | ||
} | ||
|
||
public static class ParamConverter implements ParamConverterProvider { | ||
@SuppressWarnings("unchecked") | ||
@Override | ||
public <T> javax.ws.rs.ext.ParamConverter<T> getConverter(Class<T> rawType, Type genericType, | ||
Annotation[] annotations) { | ||
if (rawType == Param.class) { | ||
return (javax.ws.rs.ext.ParamConverter<T>) new javax.ws.rs.ext.ParamConverter<Param>() { | ||
@Override | ||
public Param fromString(String value) { | ||
return null; | ||
} | ||
|
||
@Override | ||
public String toString(Param value) { | ||
if (value == null) { | ||
return null; | ||
} | ||
switch (value) { | ||
case FIRST: | ||
return "1"; | ||
case SECOND: | ||
return "2"; | ||
default: | ||
return "unexpected"; | ||
} | ||
} | ||
}; | ||
} | ||
return null; | ||
} | ||
} | ||
|
||
@Path("/echo") | ||
public static class EchoEndpoint { | ||
@Path("/param/{param}") | ||
@GET | ||
public String echoPath(@PathParam("param") String param) { | ||
return param; | ||
} | ||
|
||
@Path("/sub/param/{param}") | ||
@GET | ||
public String echoSubPath(@PathParam("param") String param) { | ||
return param; | ||
} | ||
|
||
@GET | ||
@Path("/query") | ||
public String get(@QueryParam("param") String param) { | ||
return param; | ||
} | ||
|
||
@Path("/sub/query") | ||
@GET | ||
public String getSub(@QueryParam("param") String param) { | ||
return param; | ||
} | ||
|
||
@GET | ||
@Path("/header") | ||
public String getHeader(@HeaderParam("param") String param) { | ||
return param; | ||
} | ||
|
||
@Path("/sub/header") | ||
@GET | ||
public String getSubHeader(@HeaderParam("param") String param) { | ||
return param; | ||
} | ||
|
||
@GET | ||
@Path("/cookie") | ||
public String getCookie(@CookieParam("cookie-param") String param) { | ||
return param; | ||
} | ||
|
||
@Path("/sub/cookie") | ||
@GET | ||
public String getSubCookie(@CookieParam("cookie-param") String param) { | ||
return param; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.