diff --git a/spring-web/src/test/java/org/springframework/web/service/invoker/HttpExchangeAdapterServiceMethodTests.java b/spring-web/src/test/java/org/springframework/web/service/invoker/HttpExchangeAdapterServiceMethodTests.java
deleted file mode 100644
index 053933e731..0000000000
--- a/spring-web/src/test/java/org/springframework/web/service/invoker/HttpExchangeAdapterServiceMethodTests.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2002-2023 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.web.service.invoker;
-
-import org.junit.jupiter.api.BeforeEach;
-
-/**
- * Tests for {@link HttpServiceMethod} with a blocking test {@link TestExchangeAdapter} that
- * stubs the client invocations.
- *
- * The tests do not create or invoke {@code HttpServiceMethod} directly but rather use
- * {@link HttpServiceProxyFactory} to create a service proxy in order to use a strongly
- * typed interface without the need for class casts.
- *
- * @author Olga Maciaszek-Sharma
- */
-class HttpExchangeAdapterServiceMethodTests extends HttpServiceMethodTests {
-
- @BeforeEach
- void setUp() {
- this.client = new TestExchangeAdapter();
- this.proxyFactory = HttpServiceProxyFactory.builderFor(this.client).build();
- }
-
-}
diff --git a/spring-web/src/test/java/org/springframework/web/service/invoker/HttpServiceMethodTests.java b/spring-web/src/test/java/org/springframework/web/service/invoker/HttpServiceMethodTests.java
index db3525d98b..eab3a1c425 100644
--- a/spring-web/src/test/java/org/springframework/web/service/invoker/HttpServiceMethodTests.java
+++ b/spring-web/src/test/java/org/springframework/web/service/invoker/HttpServiceMethodTests.java
@@ -19,9 +19,16 @@ package org.springframework.web.service.invoker;
import java.util.List;
import java.util.Optional;
+import io.reactivex.rxjava3.core.Completable;
+import io.reactivex.rxjava3.core.Flowable;
+import io.reactivex.rxjava3.core.Single;
import org.junit.jupiter.api.Test;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+import reactor.test.StepVerifier;
import org.springframework.core.ParameterizedTypeReference;
+import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
@@ -36,29 +43,35 @@ import static org.springframework.http.MediaType.APPLICATION_CBOR_VALUE;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
/**
- * Base class for testing {@link HttpServiceMethod} with a test {@link TestExchangeAdapter}
- * and a test {@link TestExchangeAdapter} that stub the client invocations.
+ * Tests for {@link HttpServiceMethod} with
+ * {@link TestExchangeAdapter} and {@link TestReactorExchangeAdapter}.
*
- *
- * The tests do not create or invoke {@code HttpServiceMethod} directly but rather use
- * {@link HttpServiceProxyFactory} to create a service proxy in order to use a strongly
- * typed interface without the need for class casts.
+ *
The tests do not create or invoke {@code HttpServiceMethod} directly but
+ * rather use {@link HttpServiceProxyFactory} to create a service proxy in order to
+ * use a strongly typed interface without the need for class casts.
*
* @author Rossen Stoyanchev
* @author Olga Maciaszek-Sharma
*/
-abstract class HttpServiceMethodTests {
+class HttpServiceMethodTests {
- protected static final ParameterizedTypeReference BODY_TYPE = new ParameterizedTypeReference<>() {
- };
+ private static final ParameterizedTypeReference BODY_TYPE = new ParameterizedTypeReference<>() {};
- protected TestExchangeAdapter client;
- protected HttpServiceProxyFactory proxyFactory;
+ private final TestExchangeAdapter client = new TestExchangeAdapter();
+
+ private final TestReactorExchangeAdapter reactorClient = new TestReactorExchangeAdapter();
+
+ private final HttpServiceProxyFactory proxyFactory =
+ HttpServiceProxyFactory.builder().exchangeAdapter(this.client).build();
+
+ private final HttpServiceProxyFactory reactorProxyFactory =
+ HttpServiceProxyFactory.builder().exchangeAdapter(this.reactorClient).build();
+
@Test
- void blockingService() {
- BlockingService service = this.proxyFactory.createClient(BlockingService.class);
+ void service() {
+ Service service = this.proxyFactory.createClient(Service.class);
service.execute();
@@ -66,19 +79,82 @@ abstract class HttpServiceMethodTests {
assertThat(headers).isNotNull();
String body = service.getBody();
- assertThat(body).isEqualTo(client.getInvokedMethodName());
+ assertThat(body).isEqualTo(this.client.getInvokedMethodName());
Optional optional = service.getBodyOptional();
- assertThat(optional.get()).startsWith("exchangeForBody");
+ assertThat(optional.get()).isEqualTo("exchangeForBody");
ResponseEntity entity = service.getEntity();
- assertThat(entity.getBody()).startsWith("exchangeForEntity");
+ assertThat(entity.getBody()).isEqualTo("exchangeForEntity");
ResponseEntity voidEntity = service.getVoidEntity();
assertThat(voidEntity.getBody()).isNull();
List list = service.getList();
- assertThat(list.get(0)).startsWith("exchangeForBody");
+ assertThat(list.get(0)).isEqualTo("exchangeForBody");
+ }
+
+ @Test
+ void reactorService() {
+ ReactorService service = this.reactorProxyFactory.createClient(ReactorService.class);
+
+ Mono voidMono = service.execute();
+ StepVerifier.create(voidMono).verifyComplete();
+ verifyReactorClientInvocation("exchangeForMono", null);
+
+ Mono headersMono = service.getHeaders();
+ StepVerifier.create(headersMono).expectNextCount(1).verifyComplete();
+ verifyReactorClientInvocation("exchangeForHeadersMono", null);
+
+ Mono body = service.getBody();
+ StepVerifier.create(body).expectNext("exchangeForBodyMono").verifyComplete();
+ verifyReactorClientInvocation("exchangeForBodyMono", BODY_TYPE);
+
+ Flux fluxBody = service.getFluxBody();
+ StepVerifier.create(fluxBody).expectNext("exchange", "For", "Body", "Flux").verifyComplete();
+ verifyReactorClientInvocation("exchangeForBodyFlux", BODY_TYPE);
+
+ Mono> voidEntity = service.getVoidEntity();
+ StepVerifier.create(voidEntity).expectNext(ResponseEntity.ok().build()).verifyComplete();
+ verifyReactorClientInvocation("exchangeForBodilessEntityMono", null);
+
+ Mono> entity = service.getEntity();
+ StepVerifier.create(entity).expectNext(ResponseEntity.ok("exchangeForEntityMono"));
+ verifyReactorClientInvocation("exchangeForEntityMono", BODY_TYPE);
+
+ Mono>> fluxEntity = service.getFluxEntity();
+ StepVerifier.create(fluxEntity.flatMapMany(HttpEntity::getBody))
+ .expectNext("exchange", "For", "Entity", "Flux")
+ .verifyComplete();
+ verifyReactorClientInvocation("exchangeForEntityFlux", BODY_TYPE);
+
+ assertThat(service.getDefaultMethodValue()).isEqualTo("default value");
+ }
+
+ @Test
+ void rxJavaService() {
+ RxJavaService service = this.reactorProxyFactory.createClient(RxJavaService.class);
+ Completable completable = service.execute();
+ assertThat(completable).isNotNull();
+
+ Single headersSingle = service.getHeaders();
+ assertThat(headersSingle.blockingGet()).isNotNull();
+
+ Single bodySingle = service.getBody();
+ assertThat(bodySingle.blockingGet()).isEqualTo("exchangeForBodyMono");
+
+ Flowable bodyFlow = service.getFlowableBody();
+ assertThat(bodyFlow.toList().blockingGet()).asList().containsExactly("exchange", "For", "Body", "Flux");
+
+ Single> voidEntity = service.getVoidEntity();
+ assertThat(voidEntity.blockingGet().getBody()).isNull();
+
+ Single> entitySingle = service.getEntity();
+ assertThat(entitySingle.blockingGet().getBody()).isEqualTo("exchangeForEntityMono");
+
+ Single>> entityFlow = service.getFlowableEntity();
+ Flowable body = (entityFlow.blockingGet()).getBody();
+ assertThat(body.toList().blockingGet()).containsExactly("exchange", "For", "Entity", "Flux");
}
@Test
@@ -128,13 +204,14 @@ abstract class HttpServiceMethodTests {
assertThat(requestValues.getHeaders().getAccept()).containsExactly(MediaType.APPLICATION_JSON);
}
- protected void verifyClientInvocation(String methodName, @Nullable ParameterizedTypeReference> expectedBodyType) {
- assertThat(this.client.getInvokedMethodName()).isEqualTo(methodName);
- assertThat(this.client.getBodyType()).isEqualTo(expectedBodyType);
+ protected void verifyReactorClientInvocation(String methodName, @Nullable ParameterizedTypeReference> expectedBodyType) {
+ assertThat(this.reactorClient.getInvokedMethodName()).isEqualTo(methodName);
+ assertThat(this.reactorClient.getBodyType()).isEqualTo(expectedBodyType);
}
+
@SuppressWarnings("unused")
- private interface BlockingService {
+ private interface Service {
@GetExchange
void execute();
@@ -159,6 +236,64 @@ abstract class HttpServiceMethodTests {
}
+
+ private interface ReactorService {
+
+ @GetExchange
+ Mono execute();
+
+ @GetExchange
+ Mono getHeaders();
+
+ @GetExchange
+ Mono getBody();
+
+ @GetExchange
+ Flux getFluxBody();
+
+ @GetExchange
+ Mono> getVoidEntity();
+
+ @GetExchange
+ Mono> getEntity();
+
+ @GetExchange
+ Mono>> getFluxEntity();
+
+ default String getDefaultMethodValue() {
+ return "default value";
+ }
+
+ }
+
+
+ @SuppressWarnings("unused")
+ private interface RxJavaService {
+
+ @GetExchange
+ Completable execute();
+
+ @GetExchange
+ Single getHeaders();
+
+ @GetExchange
+ Single getBody();
+
+ @GetExchange
+ Flowable getFlowableBody();
+
+ @GetExchange
+ Single> getVoidEntity();
+
+ @GetExchange
+ Single> getEntity();
+
+ @GetExchange
+ Single>> getFlowableEntity();
+
+ }
+
+
@SuppressWarnings("unused")
private interface MethodLevelAnnotatedService {
@@ -173,7 +308,6 @@ abstract class HttpServiceMethodTests {
@SuppressWarnings("unused")
@HttpExchange(url = "${baseUrl}", contentType = APPLICATION_CBOR_VALUE, accept = APPLICATION_CBOR_VALUE)
private interface TypeAndMethodLevelAnnotatedService extends MethodLevelAnnotatedService {
-
}
}
diff --git a/spring-web/src/test/java/org/springframework/web/service/invoker/ReactiveHttpServiceMethodTests.java b/spring-web/src/test/java/org/springframework/web/service/invoker/ReactiveHttpServiceMethodTests.java
deleted file mode 100644
index 83cb110c29..0000000000
--- a/spring-web/src/test/java/org/springframework/web/service/invoker/ReactiveHttpServiceMethodTests.java
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Copyright 2002-2023 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.web.service.invoker;
-
-import io.reactivex.rxjava3.core.Completable;
-import io.reactivex.rxjava3.core.Flowable;
-import io.reactivex.rxjava3.core.Single;
-import org.junit.jupiter.api.Test;
-import reactor.core.publisher.Flux;
-import reactor.core.publisher.Mono;
-import reactor.test.StepVerifier;
-
-import org.springframework.http.HttpEntity;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.ResponseEntity;
-import org.springframework.web.service.annotation.GetExchange;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-/**
- * Base class for testing reactive scenarios in {@link HttpServiceMethod} with
- * a test {@link TestReactorExchangeAdapter} that stub the client invocations.
- *
- *
- * The tests do not create or invoke {@code HttpServiceMethod} directly but rather use
- * {@link HttpServiceProxyFactory} to create a service proxy in order to use a strongly
- * typed interface without the need for class casts.
- *
- * @author Rossen Stoyanchev
- * @author Olga Maciaszek-Sharma
- */
-abstract class ReactiveHttpServiceMethodTests extends HttpServiceMethodTests {
-
- @Test
- void reactorService() {
- ReactorService service = proxyFactory.createClient(ReactorService.class);
-
- Mono voidMono = service.execute();
- StepVerifier.create(voidMono).verifyComplete();
- verifyClientInvocation("exchangeForMono", null);
-
- Mono headersMono = service.getHeaders();
- StepVerifier.create(headersMono).expectNextCount(1).verifyComplete();
- verifyClientInvocation("exchangeForHeadersMono", null);
-
- Mono body = service.getBody();
- StepVerifier.create(body).expectNext("exchangeForBodyMono").verifyComplete();
- verifyClientInvocation("exchangeForBodyMono", BODY_TYPE);
-
- Flux fluxBody = service.getFluxBody();
- StepVerifier.create(fluxBody).expectNext("exchange", "For", "Body", "Flux").verifyComplete();
- verifyClientInvocation("exchangeForBodyFlux", BODY_TYPE);
-
- Mono> voidEntity = service.getVoidEntity();
- StepVerifier.create(voidEntity).expectNext(ResponseEntity.ok().build()).verifyComplete();
- verifyClientInvocation("exchangeForBodilessEntityMono", null);
-
- Mono> entity = service.getEntity();
- StepVerifier.create(entity).expectNext(ResponseEntity.ok("exchangeForEntityMono"));
- verifyClientInvocation("exchangeForEntityMono", BODY_TYPE);
-
- Mono>> fluxEntity = service.getFluxEntity();
- StepVerifier.create(fluxEntity.flatMapMany(HttpEntity::getBody))
- .expectNext("exchange", "For", "Entity", "Flux")
- .verifyComplete();
- verifyClientInvocation("exchangeForEntityFlux", BODY_TYPE);
-
- assertThat(service.getDefaultMethodValue()).isEqualTo("default value");
- }
-
- @Test
- void rxJavaService() {
- RxJavaService service = this.proxyFactory.createClient(RxJavaService.class);
- Completable completable = service.execute();
- assertThat(completable).isNotNull();
-
- Single headersSingle = service.getHeaders();
- assertThat(headersSingle.blockingGet()).isNotNull();
-
- Single bodySingle = service.getBody();
- assertThat(bodySingle.blockingGet()).isEqualTo("exchangeForBodyMono");
-
- Flowable bodyFlow = service.getFlowableBody();
- assertThat(bodyFlow.toList().blockingGet()).asList().containsExactly("exchange", "For", "Body", "Flux");
-
- Single> voidEntity = service.getVoidEntity();
- assertThat(voidEntity.blockingGet().getBody()).isNull();
-
- Single> entitySingle = service.getEntity();
- assertThat(entitySingle.blockingGet().getBody()).isEqualTo("exchangeForEntityMono");
-
- Single>> entityFlow = service.getFlowableEntity();
- Flowable body = (entityFlow.blockingGet()).getBody();
- assertThat(body.toList().blockingGet()).containsExactly("exchange", "For", "Entity", "Flux");
- }
-
- private interface ReactorService {
-
- @GetExchange
- Mono execute();
-
- @GetExchange
- Mono getHeaders();
-
- @GetExchange
- Mono getBody();
-
- @GetExchange
- Flux getFluxBody();
-
- @GetExchange
- Mono> getVoidEntity();
-
- @GetExchange
- Mono> getEntity();
-
- @GetExchange
- Mono>> getFluxEntity();
-
- default String getDefaultMethodValue() {
- return "default value";
- }
-
- }
-
- @SuppressWarnings("unused")
- private interface RxJavaService {
-
- @GetExchange
- Completable execute();
-
- @GetExchange
- Single getHeaders();
-
- @GetExchange
- Single getBody();
-
- @GetExchange
- Flowable getFlowableBody();
-
- @GetExchange
- Single> getVoidEntity();
-
- @GetExchange
- Single> getEntity();
-
- @GetExchange
- Single>> getFlowableEntity();
-
- }
-
-}
diff --git a/spring-web/src/test/java/org/springframework/web/service/invoker/ReactorExchangeAdapterHttpServiceMethodTests.java b/spring-web/src/test/java/org/springframework/web/service/invoker/ReactorExchangeAdapterHttpServiceMethodTests.java
deleted file mode 100644
index 8a7aecda3e..0000000000
--- a/spring-web/src/test/java/org/springframework/web/service/invoker/ReactorExchangeAdapterHttpServiceMethodTests.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2002-2023 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.web.service.invoker;
-
-import org.junit.jupiter.api.BeforeEach;
-
-/**
- * Tests for {@link HttpServiceMethod} with an {@link HttpExchangeAdapter}
- * build from a test {@link TestReactorExchangeAdapter} that stubs the client invocations.
- *
- * The tests do not create or invoke {@code HttpServiceMethod} directly but rather use
- * {@link HttpServiceProxyFactory} to create a service proxy in order to use a strongly
- * typed interface without the need for class casts.
- *
- * @author Olga Maciaszek-Sharma
- */
-public class ReactorExchangeAdapterHttpServiceMethodTests extends ReactiveHttpServiceMethodTests {
-
- @BeforeEach
- void setUp() {
- this.client = new TestReactorExchangeAdapter();
- this.proxyFactory = HttpServiceProxyFactory.builder().exchangeAdapter(this.client).build();
- }
-
-}