diff --git a/bom/runtime/pom.xml b/bom/runtime/pom.xml
index bc49223a587c6..58a718106ff2d 100644
--- a/bom/runtime/pom.xml
+++ b/bom/runtime/pom.xml
@@ -1033,6 +1033,11 @@
quarkus-junit5-mockito
${project.version}
+
+ io.quarkus
+ quarkus-test-rest-client
+ ${project.version}
+
io.quarkus
quarkus-arquillian
diff --git a/integration-tests/rest-client/pom.xml b/integration-tests/rest-client/pom.xml
index b271a14d68b0e..e7f802dc68cef 100644
--- a/integration-tests/rest-client/pom.xml
+++ b/integration-tests/rest-client/pom.xml
@@ -34,8 +34,7 @@
io.quarkus
- quarkus-junit5
- test
+ quarkus-test-rest-client
io.rest-assured
diff --git a/integration-tests/rest-client/src/main/java/io/quarkus/it/rest/client/MultipartService.java b/integration-tests/rest-client/src/main/java/io/quarkus/it/rest/client/MultipartService.java
index 26021b4751c24..04945608d6bdc 100644
--- a/integration-tests/rest-client/src/main/java/io/quarkus/it/rest/client/MultipartService.java
+++ b/integration-tests/rest-client/src/main/java/io/quarkus/it/rest/client/MultipartService.java
@@ -1,5 +1,6 @@
package io.quarkus.it.rest.client;
+import javax.enterprise.context.ApplicationScoped;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
@@ -11,6 +12,7 @@
@Path("/echo")
@RegisterRestClient
+@ApplicationScoped
public interface MultipartService {
@POST
@@ -18,4 +20,4 @@ public interface MultipartService {
@Produces(MediaType.TEXT_PLAIN)
String sendMultipartData(@MultipartForm MultipartBody data);
-}
\ No newline at end of file
+}
diff --git a/integration-tests/rest-client/src/main/java/io/quarkus/it/rest/client/server/AnotherEchoService.java b/integration-tests/rest-client/src/main/java/io/quarkus/it/rest/client/server/AnotherEchoService.java
new file mode 100644
index 0000000000000..3869a572949ea
--- /dev/null
+++ b/integration-tests/rest-client/src/main/java/io/quarkus/it/rest/client/server/AnotherEchoService.java
@@ -0,0 +1,19 @@
+package io.quarkus.it.rest.client.server;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+@Path("/another/new")
+public class AnotherEchoService {
+
+ @Path("/echo")
+ @POST
+ @Consumes(MediaType.MULTIPART_FORM_DATA)
+ @Produces(MediaType.TEXT_PLAIN)
+ public String echo(String requestBody) throws Exception {
+ return "another";
+ }
+}
diff --git a/integration-tests/rest-client/src/main/java/io/quarkus/it/rest/client/server/OtherEchoService.java b/integration-tests/rest-client/src/main/java/io/quarkus/it/rest/client/server/OtherEchoService.java
new file mode 100644
index 0000000000000..64b18ce5a5b31
--- /dev/null
+++ b/integration-tests/rest-client/src/main/java/io/quarkus/it/rest/client/server/OtherEchoService.java
@@ -0,0 +1,18 @@
+package io.quarkus.it.rest.client.server;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+@Path("/other/echo")
+public class OtherEchoService {
+
+ @POST
+ @Consumes(MediaType.MULTIPART_FORM_DATA)
+ @Produces(MediaType.TEXT_PLAIN)
+ public String echo(String requestBody) throws Exception {
+ return "other";
+ }
+}
diff --git a/integration-tests/rest-client/src/test/java/io/quarkus/it/rest/client/MultipartResourceTest.java b/integration-tests/rest-client/src/test/java/io/quarkus/it/rest/client/MultipartResourceTest.java
index 6a3f6cbd217df..baa13483f5ac5 100644
--- a/integration-tests/rest-client/src/test/java/io/quarkus/it/rest/client/MultipartResourceTest.java
+++ b/integration-tests/rest-client/src/test/java/io/quarkus/it/rest/client/MultipartResourceTest.java
@@ -3,13 +3,23 @@
import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.containsString;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import org.junit.jupiter.api.MethodOrderer;
+import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestMethodOrder;
+import io.quarkus.test.junit.DisabledOnNativeImage;
import io.quarkus.test.junit.QuarkusTest;
+import io.quarkus.test.restclient.RestClientTestSupport;
+@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@QuarkusTest
public class MultipartResourceTest {
+ @Order(3) // execute this last to make sure that the reset of the base URL is properly performed automatically
@Test
public void testMultipartDataIsSent() {
given()
@@ -23,4 +33,30 @@ public void testMultipartDataIsSent() {
containsString("greeting.txt"));
}
+ @DisabledOnNativeImage
+ @Order(1)
+ @Test
+ public void testCustomEcho() throws URISyntaxException {
+ RestClientTestSupport.setBaseURI(MultipartService.class, new URI(System.getProperty("test.url") + "/other"));
+ given()
+ .header("Content-Type", "text/plain")
+ .when().post("/client/multipart")
+ .then()
+ .statusCode(200)
+ .body(containsString("other"));
+ }
+
+ @DisabledOnNativeImage
+ @Order(2)
+ @Test
+ public void testAnotherCustomEcho() throws URISyntaxException {
+ RestClientTestSupport.setBaseURI(MultipartService.class, new URI(System.getProperty("test.url") + "/another/new"));
+ given()
+ .header("Content-Type", "text/plain")
+ .when().post("/client/multipart")
+ .then()
+ .statusCode(200)
+ .body(containsString("another"));
+ }
+
}
diff --git a/test-framework/pom.xml b/test-framework/pom.xml
index 4f10d79f93fe2..116d7ebecb81d 100644
--- a/test-framework/pom.xml
+++ b/test-framework/pom.xml
@@ -28,6 +28,7 @@
maven
vault
ldap
+ rest-client
diff --git a/test-framework/rest-client/pom.xml b/test-framework/rest-client/pom.xml
new file mode 100644
index 0000000000000..06690aedc3059
--- /dev/null
+++ b/test-framework/rest-client/pom.xml
@@ -0,0 +1,57 @@
+
+
+ 4.0.0
+
+
+ io.quarkus
+ quarkus-test-framework
+ 999-SNAPSHOT
+ ../
+
+
+ quarkus-test-rest-client
+ Quarkus - Test framework - REST Client
+
+
+ io.quarkus
+ quarkus-junit5
+
+
+ io.quarkus
+ quarkus-arc-deployment
+
+
+ org.jboss.resteasy
+ resteasy-client-microprofile
+
+
+ org.jboss.spec.javax.interceptor
+
+ jboss-interceptors-api_1.2_spec
+
+
+
+ org.jboss.resteasy
+ resteasy-cdi
+
+
+
+
+ org.apache.httpcomponents
+ httpasyncclient
+
+
+ commons-logging
+ commons-logging
+
+
+
+
+ org.jboss.logging
+ commons-logging-jboss-logging
+
+
+
+
diff --git a/test-framework/rest-client/src/main/java/io/quarkus/test/restclient/RestClientTestSupport.java b/test-framework/rest-client/src/main/java/io/quarkus/test/restclient/RestClientTestSupport.java
new file mode 100644
index 0000000000000..8d495742dbb65
--- /dev/null
+++ b/test-framework/rest-client/src/main/java/io/quarkus/test/restclient/RestClientTestSupport.java
@@ -0,0 +1,235 @@
+package io.quarkus.test.restclient;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Consumer;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.inject.spi.Bean;
+import javax.inject.Singleton;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.UriBuilder;
+
+import org.eclipse.microprofile.rest.client.inject.RestClient;
+import org.jboss.resteasy.client.jaxrs.internal.ClientWebTarget;
+import org.jboss.resteasy.client.jaxrs.internal.proxy.ClientInvoker;
+import org.jboss.resteasy.client.jaxrs.internal.proxy.ClientProxy;
+import org.jboss.resteasy.client.jaxrs.internal.proxy.MethodInvoker;
+import org.jboss.resteasy.microprofile.client.ProxyInvocationHandler;
+import org.jboss.resteasy.microprofile.client.impl.MpClientWebTarget;
+import org.jboss.resteasy.specimpl.ResteasyUriBuilderImpl;
+
+import io.quarkus.arc.Arc;
+import io.quarkus.arc.runtime.ClientProxyUnwrapper;
+
+/**
+ * Provides a way for tests to change the baseURI of a rest-client
+ */
+public class RestClientTestSupport {
+
+ private static final Map, Object> restClientClassToObject = new ConcurrentHashMap<>();
+ private static final Map