mirror of
https://github.com/jlengrand/quarkus.git
synced 2026-03-10 08:41:22 +00:00
Merge pull request #7270 from aguibert/rest-client-native-providers
Transfer providers discovered at build-time to new ClientBuilder instances
This commit is contained in:
@@ -83,6 +83,9 @@ class RestClientProcessor {
|
||||
private static final DotName REGISTER_PROVIDER = DotName.createSimple(RegisterProvider.class.getName());
|
||||
private static final DotName REGISTER_PROVIDERS = DotName.createSimple(RegisterProviders.class.getName());
|
||||
|
||||
private static final DotName CLIENT_REQUEST_FILTER = DotName.createSimple(ClientRequestFilter.class.getName());
|
||||
private static final DotName CLIENT_RESPONSE_FILTER = DotName.createSimple(ClientResponseFilter.class.getName());
|
||||
|
||||
private static final String PROVIDERS_SERVICE_FILE = "META-INF/services/" + Providers.class.getName();
|
||||
|
||||
@BuildStep
|
||||
@@ -341,6 +344,15 @@ class RestClientProcessor {
|
||||
reflectiveClass
|
||||
.produce(new ReflectiveClassBuildItem(false, false, annotationInstance.value().asClass().toString()));
|
||||
}
|
||||
|
||||
// now retain all un-annotated implementations of ClientRequestFilter and ClientResponseFilter
|
||||
// in case they are programmatically registered by applications
|
||||
for (ClassInfo info : index.getAllKnownImplementors(CLIENT_REQUEST_FILTER)) {
|
||||
reflectiveClass.produce(new ReflectiveClassBuildItem(false, false, info.name().toString()));
|
||||
}
|
||||
for (ClassInfo info : index.getAllKnownImplementors(CLIENT_RESPONSE_FILTER)) {
|
||||
reflectiveClass.produce(new ReflectiveClassBuildItem(false, false, info.name().toString()));
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isRestClientInterface(IndexView index, ClassInfo classInfo) {
|
||||
|
||||
@@ -18,11 +18,16 @@ import io.quarkus.runtime.annotations.Recorder;
|
||||
|
||||
@Recorder
|
||||
public class RestClientRecorder {
|
||||
|
||||
public static ResteasyProviderFactory providerFactory;
|
||||
public static boolean SSL_ENABLED;
|
||||
|
||||
public void setRestClientBuilderResolver() {
|
||||
RestClientBuilderResolver.setInstance(new BuilderResolver());
|
||||
}
|
||||
|
||||
public void setSslEnabled(boolean sslEnabled) {
|
||||
SSL_ENABLED = sslEnabled;
|
||||
RestClientBuilderImpl.setSslEnabled(sslEnabled);
|
||||
}
|
||||
|
||||
@@ -57,6 +62,7 @@ public class RestClientRecorder {
|
||||
}
|
||||
|
||||
RestClientBuilderImpl.setProviderFactory(clientProviderFactory);
|
||||
providerFactory = clientProviderFactory;
|
||||
}
|
||||
|
||||
private static void registerProviders(ResteasyProviderFactory clientProviderFactory, Set<String> providersToRegister,
|
||||
|
||||
@@ -2,16 +2,29 @@ package io.quarkus.restclient.runtime.graal;
|
||||
|
||||
import javax.ws.rs.client.ClientBuilder;
|
||||
|
||||
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
|
||||
import org.jboss.resteasy.client.jaxrs.engines.URLConnectionClientEngineBuilder;
|
||||
import org.jboss.resteasy.client.jaxrs.internal.LocalResteasyProviderFactory;
|
||||
import org.jboss.resteasy.client.jaxrs.internal.ResteasyClientBuilderImpl;
|
||||
|
||||
import com.oracle.svm.core.annotate.Substitute;
|
||||
import com.oracle.svm.core.annotate.TargetClass;
|
||||
|
||||
import io.quarkus.restclient.runtime.RestClientRecorder;
|
||||
|
||||
@TargetClass(ClientBuilder.class)
|
||||
final class ClientBuilderReplacement {
|
||||
|
||||
@Substitute
|
||||
public static ClientBuilder newBuilder() {
|
||||
return new ResteasyClientBuilderImpl();
|
||||
ResteasyClientBuilder client = new ResteasyClientBuilderImpl();
|
||||
client.providerFactory(new LocalResteasyProviderFactory(RestClientRecorder.providerFactory));
|
||||
if (!RestClientRecorder.SSL_ENABLED) {
|
||||
client.httpEngine(new URLConnectionClientEngineBuilder().resteasyClientBuilder(client).build());
|
||||
client.sslContext(null);
|
||||
client.trustStore(null);
|
||||
client.keyStore(null, "");
|
||||
}
|
||||
return client;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
package io.quarkus.it.rest;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.PreDestroy;
|
||||
import javax.enterprise.context.ApplicationScoped;
|
||||
import javax.enterprise.inject.Produces;
|
||||
import javax.ws.rs.client.Client;
|
||||
import javax.ws.rs.client.ClientBuilder;
|
||||
|
||||
@ApplicationScoped
|
||||
public class ClientProducer {
|
||||
private Client client;
|
||||
|
||||
@PostConstruct
|
||||
void init() {
|
||||
client = ClientBuilder.newClient().register(LoggingFilter.class);
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
void close() {
|
||||
if (client != null) {
|
||||
client.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Produces
|
||||
@ApplicationScoped
|
||||
public Client getClient() {
|
||||
return client;
|
||||
}
|
||||
}
|
||||
@@ -6,11 +6,15 @@ import java.util.Map;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Provider;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.client.Client;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
import org.eclipse.microprofile.config.ConfigProvider;
|
||||
import org.eclipse.microprofile.config.inject.ConfigProperty;
|
||||
import org.eclipse.microprofile.rest.client.RestClientBuilder;
|
||||
import org.eclipse.microprofile.rest.client.inject.RestClient;
|
||||
|
||||
@@ -35,6 +39,13 @@ public class ClientResource {
|
||||
@RestClient
|
||||
RestClientBaseUriConfigKeyInterface restClientBaseUriConfigKeyInterface;
|
||||
|
||||
@Inject
|
||||
@ConfigProperty(name = "loopback/mp-rest/url", defaultValue = "http://localhost:8080/loopback")
|
||||
Provider<String> loopbackEndpoint;
|
||||
|
||||
@Inject
|
||||
Client client;
|
||||
|
||||
@GET
|
||||
@Path("/annotation/configKey")
|
||||
public String configKey() {
|
||||
@@ -140,4 +151,32 @@ public class ClientResource {
|
||||
public String getDefaultInterfaceScope() {
|
||||
return Arc.container().instance(RestClientInterface.class, RestClient.LITERAL).getBean().getScope().getName();
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/jaxrs-client")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Greeting testJaxrsClient() throws ClassNotFoundException {
|
||||
Greeting greeting = client.target(loopbackEndpoint.get())
|
||||
.request()
|
||||
.get(Greeting.class);
|
||||
// The LoggingFilter should be programmatically registered in io.quarkus.it.rest.ClientProducer.init()
|
||||
if (!client.getConfiguration().isRegistered(Class.forName("io.quarkus.it.rest.LoggingFilter")))
|
||||
throw new IllegalStateException("LoggingFilter should be registered on injected Client");
|
||||
if (getFilterCount() != 2)
|
||||
throw new IllegalStateException("Call count should have been 2 but was " + getFilterCount());
|
||||
return greeting;
|
||||
}
|
||||
|
||||
private int getFilterCount() {
|
||||
try {
|
||||
// Must use reflection to check filter call count to ensure that
|
||||
// completely decoupled filters are not removed in native mode
|
||||
return Class.forName("io.quarkus.it.rest.LoggingFilter")
|
||||
.getDeclaredField("CALL_COUNT")
|
||||
.getInt(null);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package io.quarkus.it.rest;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
import javax.json.bind.annotation.JsonbCreator;
|
||||
import javax.json.bind.annotation.JsonbProperty;
|
||||
|
||||
public class Greeting {
|
||||
|
||||
private final String message;
|
||||
private final LocalDate date;
|
||||
|
||||
@JsonbCreator
|
||||
public Greeting(@JsonbProperty("message") String message, @JsonbProperty("date") LocalDate date) {
|
||||
this.message = message;
|
||||
this.date = date;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public LocalDate getDate() {
|
||||
return date;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package io.quarkus.it.rest;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.ws.rs.client.ClientRequestContext;
|
||||
import javax.ws.rs.client.ClientRequestFilter;
|
||||
import javax.ws.rs.client.ClientResponseContext;
|
||||
import javax.ws.rs.client.ClientResponseFilter;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class LoggingFilter
|
||||
implements ClientRequestFilter, ClientResponseFilter {
|
||||
private final Logger log = LoggerFactory.getLogger(getClass());
|
||||
|
||||
public static int CALL_COUNT = 0;
|
||||
|
||||
@Override
|
||||
public void filter(ClientRequestContext requestContext, ClientResponseContext responseContext)
|
||||
throws IOException {
|
||||
CALL_COUNT++;
|
||||
log.info("<< {} {}", responseContext.getStatusInfo().getStatusCode(),
|
||||
responseContext.getStatusInfo().getReasonPhrase());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void filter(ClientRequestContext requestContext)
|
||||
throws IOException {
|
||||
CALL_COUNT++;
|
||||
log.info(">> {} {}", requestContext.getMethod(), requestContext.getUri());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package io.quarkus.it.rest;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
@Path("/loopback")
|
||||
public class LoopbackResource {
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Greeting hello() {
|
||||
return new Greeting("hello self", LocalDate.of(2020, 02, 13));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,6 +3,7 @@ io.quarkus.it.rest.RestInterface/mp-rest/scope=javax.inject.Singleton
|
||||
io.quarkus.it.rest.RestClientInterface/mp-rest/url=${test.url}
|
||||
restClientConfigKey/mp-rest/url=${test.url}
|
||||
restClientBaseUriConfigKey/mp-rest/url=${test.url}
|
||||
loopback/mp-rest/url=${test.url}/loopback
|
||||
|
||||
org.eclipse.microprofile.rest.client.propagateHeaders=header-name
|
||||
# Disabled by default as it establishes external connections.
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package io.quarkus.it.main;
|
||||
|
||||
import static io.restassured.RestAssured.given;
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
import java.util.List;
|
||||
@@ -118,6 +120,16 @@ public class RestClientTestCase {
|
||||
Assertions.assertEquals("javax.enterprise.context.Dependent", responseWithDefaultScope);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testJaxrsClientWithFilters() {
|
||||
given()
|
||||
.when().get("/client/jaxrs-client")
|
||||
.then()
|
||||
.statusCode(200)
|
||||
.body(containsString("hello"))
|
||||
.body(containsString("2020-02-13"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Disabled("Disabled by default as it establishes external connections, uncomment when you want to test SSL support")
|
||||
public void testDegradedSslSupport() {
|
||||
|
||||
Reference in New Issue
Block a user