Introduce hints in RestClient API

This commit introduces hints in RestClient API for
SmartHttpMessageConverters supporting them.

Closes gh-34924
This commit is contained in:
Sébastien Deleuze
2025-06-06 12:27:46 +02:00
parent 72601b6948
commit 977792009d
5 changed files with 141 additions and 21 deletions

View File

@@ -28,9 +28,11 @@ import java.util.Map;
import java.util.function.Consumer;
import java.util.stream.Stream;
import com.fasterxml.jackson.annotation.JsonView;
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
import okhttp3.mockwebserver.RecordedRequest;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
@@ -528,6 +530,35 @@ class RestClientIntegrationTests {
});
}
@ParameterizedRestClientTest
void postUserAsJsonWithJsonView(ClientHttpRequestFactory requestFactory) {
startServer(requestFactory);
prepareResponse(response -> response.setHeader("Content-Type", "application/json")
.setBody("{\"username\":\"USERNAME\"}"));
User result = this.restClient.post()
.uri("/user/capitalize")
.accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON)
.hint(JsonView.class.getName(), PublicView.class)
.body(new User("username", "password"))
.retrieve()
.body(User.class);
assertThat(result).isNotNull();
assertThat(result.username()).isEqualTo("USERNAME");
assertThat(result.password()).isNull();
expectRequestCount(1);
expectRequest(request -> {
assertThat(request.getPath()).isEqualTo("/user/capitalize");
assertThat(request.getBody().readUtf8()).isEqualTo("{\"username\":\"username\"}");
assertThat(request.getHeader(HttpHeaders.ACCEPT)).isEqualTo("application/json");
assertThat(request.getHeader(HttpHeaders.CONTENT_TYPE)).isEqualTo("application/json");
});
}
@ParameterizedRestClientTest // gh-31361
public void postForm(ClientHttpRequestFactory requestFactory) {
startServer(requestFactory);
@@ -1150,4 +1181,8 @@ class RestClientIntegrationTests {
}
}
interface PublicView {}
record User(@JsonView(PublicView.class) String username, @Nullable String password) {}
}

View File

@@ -22,6 +22,9 @@ import io.mockk.verify
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import org.springframework.core.ParameterizedTypeReference
import kotlin.reflect.KType
import kotlin.reflect.jvm.jvmName
import kotlin.reflect.typeOf
/**
* Mock object based tests for [RestClient] Kotlin extensions
@@ -38,31 +41,36 @@ class RestClientExtensionsTests {
fun `RequestBodySpec#body with reified type parameters`() {
val body = mockk<List<Foo>>()
requestBodySpec.bodyWithType(body)
verify { requestBodySpec.body(body, object : ParameterizedTypeReference<List<Foo>>() {}) }
verify { requestBodySpec.hint(KType::class.jvmName, typeOf<List<Foo>>())
.body(body, object : ParameterizedTypeReference<List<Foo>>() {})
}
}
@Test
fun `ResponseSpec#body with reified type parameters`() {
responseSpec.body<List<Foo>>()
verify { responseSpec.body(object : ParameterizedTypeReference<List<Foo>>() {}) }
verify { responseSpec.hint(KType::class.jvmName, typeOf<List<Foo>>())
.body(object : ParameterizedTypeReference<List<Foo>>() {}) }
}
@Test
fun `ResponseSpec#requiredBody with reified type parameters`() {
responseSpec.requiredBody<List<Foo>>()
verify { responseSpec.body(object : ParameterizedTypeReference<List<Foo>>() {}) }
verify { responseSpec.hint(KType::class.jvmName, typeOf<List<Foo>>())
.body(object : ParameterizedTypeReference<List<Foo>>() {}) }
}
@Test
fun `ResponseSpec#requiredBody with null response throws NoSuchElementException`() {
every { responseSpec.body(any<ParameterizedTypeReference<Foo>>()) } returns null
every { responseSpec.hint(KType::class.jvmName, any()).body(any<ParameterizedTypeReference<Foo>>()) } returns null
assertThrows<NoSuchElementException> { responseSpec.requiredBody<Foo>() }
}
@Test
fun `ResponseSpec#toEntity with reified type parameters`() {
responseSpec.toEntity<List<Foo>>()
verify { responseSpec.toEntity(object : ParameterizedTypeReference<List<Foo>>() {}) }
verify { responseSpec.hint(KType::class.jvmName, typeOf<List<Foo>>())
.toEntity(object : ParameterizedTypeReference<List<Foo>>() {}) }
}
private class Foo