Skip to content

Commit dcb9383

Browse files
sdeleuzesbrannen
authored andcommitted
Add a requiredExchange extension to RestClient
Closes gh-34692
1 parent f8a3077 commit dcb9383

File tree

2 files changed

+36
-3
lines changed

2 files changed

+36
-3
lines changed

Diff for: spring-web/src/main/kotlin/org/springframework/web/client/RestClientExtensions.kt

+14-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2024 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -18,6 +18,8 @@ package org.springframework.web.client
1818

1919
import org.springframework.core.ParameterizedTypeReference
2020
import org.springframework.http.ResponseEntity
21+
import org.springframework.web.client.RestClient.RequestHeadersSpec
22+
import org.springframework.web.client.RestClient.RequestHeadersSpec.ExchangeFunction
2123

2224
/**
2325
* Extension for [RestClient.RequestBodySpec.body] providing a `bodyWithType<Foo>(...)` variant
@@ -51,6 +53,15 @@ inline fun <reified T : Any> RestClient.ResponseSpec.body(): T? =
5153
inline fun <reified T : Any> RestClient.ResponseSpec.requiredBody(): T =
5254
body(object : ParameterizedTypeReference<T>() {}) ?: throw NoSuchElementException("Response body is required")
5355

56+
/**
57+
* Extension for [RestClient.RequestHeadersSpec.exchange] providing a `requiredExchange(...)` variant with a
58+
* non-nullable return value.
59+
* @throws NoSuchElementException if there is no response value
60+
* @since 6.2.6
61+
*/
62+
fun <T: Any> RequestHeadersSpec<*>.requiredExchange(exchangeFunction: ExchangeFunction<T>, close: Boolean = true): T =
63+
exchange(exchangeFunction, close) ?: throw NoSuchElementException("Response value is required")
64+
5465
/**
5566
* Extension for [RestClient.ResponseSpec.toEntity] providing a `toEntity<Foo>()` variant
5667
* leveraging Kotlin reified type parameters. This extension is not subject to type
@@ -60,4 +71,5 @@ inline fun <reified T : Any> RestClient.ResponseSpec.requiredBody(): T =
6071
* @since 6.1
6172
*/
6273
inline fun <reified T : Any> RestClient.ResponseSpec.toEntity(): ResponseEntity<T> =
63-
toEntity(object : ParameterizedTypeReference<T>() {})
74+
toEntity(object : ParameterizedTypeReference<T>() {})
75+

Diff for: spring-web/src/test/kotlin/org/springframework/web/client/RestClientExtensionsTests.kt

+22-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2024 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -19,9 +19,12 @@ package org.springframework.web.client
1919
import io.mockk.every
2020
import io.mockk.mockk
2121
import io.mockk.verify
22+
import org.assertj.core.api.Assertions.assertThat
2223
import org.junit.jupiter.api.Test
2324
import org.junit.jupiter.api.assertThrows
2425
import org.springframework.core.ParameterizedTypeReference
26+
import org.springframework.http.HttpRequest
27+
import org.springframework.web.client.RestClient.RequestHeadersSpec
2528

2629
/**
2730
* Mock object based tests for [RestClient] Kotlin extensions
@@ -59,6 +62,24 @@ class RestClientExtensionsTests {
5962
assertThrows<NoSuchElementException> { responseSpec.requiredBody<Foo>() }
6063
}
6164

65+
@Test
66+
fun `RequestHeadersSpec#requiredExchange`() {
67+
val foo = Foo()
68+
every { requestBodySpec.exchange(any<RequestHeadersSpec.ExchangeFunction<Foo>>(), any()) } returns foo
69+
val exchangeFunction: (HttpRequest, RequestHeadersSpec.ConvertibleClientHttpResponse) -> Foo? =
70+
{ request, response -> foo }
71+
val value = requestBodySpec.requiredExchange(exchangeFunction)
72+
assertThat(value).isEqualTo(foo)
73+
}
74+
75+
@Test
76+
fun `RequestHeadersSpec#requiredExchange with null response throws NoSuchElementException`() {
77+
every { requestBodySpec.exchange(any<RequestHeadersSpec.ExchangeFunction<Foo>>(), any()) } returns null
78+
val exchangeFunction: (HttpRequest, RequestHeadersSpec.ConvertibleClientHttpResponse) -> Foo? =
79+
{ request, response -> null }
80+
assertThrows<NoSuchElementException> { requestBodySpec.requiredExchange(exchangeFunction) }
81+
}
82+
6283
@Test
6384
fun `ResponseSpec#toEntity with reified type parameters`() {
6485
responseSpec.toEntity<List<Foo>>()

0 commit comments

Comments
 (0)