Skip to content

Commit 02d0031

Browse files
committed
Move ServerWebExchange Kotlin extensions
This commit moves ServerWebExchange Kotlin extensions where they belong: in the spring-web module with the org.springframework.web.server package, like ServerWebExchange itself. The extensions in the wrong location are deprecated and semi-automated migration to the new variants is made possible via @deprecated + ReplaceWith(...). Some tests have been added as well. Closes gh-31046
1 parent 57f675c commit 02d0031

File tree

3 files changed

+179
-1
lines changed

3 files changed

+179
-1
lines changed
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
* Copyright 2002-2023 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.web.server
18+
19+
import kotlinx.coroutines.Dispatchers
20+
import kotlinx.coroutines.reactive.awaitSingle
21+
import kotlinx.coroutines.reactor.mono
22+
import org.springframework.http.codec.multipart.Part
23+
import org.springframework.util.MultiValueMap
24+
import java.security.Principal
25+
26+
/**
27+
* Coroutines variant of [ServerWebExchange.getFormData].
28+
*
29+
* @author Sebastien Deleuze
30+
* @since 6.1
31+
*/
32+
suspend fun ServerWebExchange.awaitFormData(): MultiValueMap<String, String> =
33+
this.formData.awaitSingle()
34+
35+
/**
36+
* Coroutines variant of [ServerWebExchange.getMultipartData].
37+
*
38+
* @author Sebastien Deleuze
39+
* @since 6.1
40+
*/
41+
suspend fun ServerWebExchange.awaitMultipartData(): MultiValueMap<String, Part> =
42+
this.multipartData.awaitSingle()
43+
44+
/**
45+
* Coroutines variant of [ServerWebExchange.getPrincipal].
46+
*
47+
* @author Sebastien Deleuze
48+
* @since 6.1
49+
*/
50+
suspend fun <T : Principal> ServerWebExchange.awaitPrincipal(): T =
51+
this.getPrincipal<T>().awaitSingle()
52+
53+
/**
54+
* Coroutines variant of [ServerWebExchange.getSession].
55+
*
56+
* @author Sebastien Deleuze
57+
* @since 6.1
58+
*/
59+
suspend fun ServerWebExchange.awaitSession(): WebSession =
60+
this.session.awaitSingle()
61+
62+
/**
63+
* Coroutines variant of [ServerWebExchange.Builder.principal].
64+
*
65+
* @author Sebastien Deleuze
66+
* @since 6.1
67+
*/
68+
fun ServerWebExchange.Builder.principal(supplier: suspend () -> Principal): ServerWebExchange.Builder
69+
= principal(mono(Dispatchers.Unconfined) { supplier.invoke() })
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*
2+
* Copyright 2002-2023 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.web.server
18+
19+
import io.mockk.every
20+
import io.mockk.mockk
21+
import io.mockk.verify
22+
import kotlinx.coroutines.runBlocking
23+
import org.assertj.core.api.Assertions.assertThat
24+
import org.junit.jupiter.api.Test
25+
import org.springframework.http.codec.multipart.Part
26+
import org.springframework.util.MultiValueMap
27+
import reactor.core.publisher.Mono
28+
import java.security.Principal
29+
30+
/**
31+
* Mock object based tests for [ServerWebExchange] Kotlin extensions
32+
*
33+
* @author Sebastien Deleuze
34+
*/
35+
class ServerWebExchangeExtensionsTest {
36+
37+
@Test
38+
fun `awaitFormData extension`() {
39+
val exchange = mockk<ServerWebExchange>()
40+
val multiMap = mockk<MultiValueMap<String, String>>()
41+
every { exchange.formData } returns Mono.just(multiMap)
42+
runBlocking {
43+
assertThat(exchange.awaitFormData()).isEqualTo(multiMap)
44+
}
45+
}
46+
47+
@Test
48+
fun `awaitMultipartData extension`() {
49+
val exchange = mockk<ServerWebExchange>()
50+
val multiMap = mockk<MultiValueMap<String, Part>>()
51+
every { exchange.multipartData } returns Mono.just(multiMap)
52+
runBlocking {
53+
assertThat(exchange.awaitMultipartData()).isEqualTo(multiMap)
54+
}
55+
}
56+
57+
@Test
58+
fun `awaitPrincipal extension`() {
59+
val exchange = mockk<ServerWebExchange>()
60+
val principal = mockk<Principal>()
61+
every { exchange.getPrincipal<Principal>() } returns Mono.just(principal)
62+
runBlocking {
63+
assertThat(exchange.awaitPrincipal<Principal>()).isEqualTo(principal)
64+
}
65+
verify { exchange.getPrincipal<Principal>() }
66+
}
67+
68+
@Test
69+
fun `awaitSession extension`() {
70+
val exchange = mockk<ServerWebExchange>()
71+
val session = mockk<WebSession>()
72+
every { exchange.session } returns Mono.just(session)
73+
runBlocking {
74+
assertThat(exchange.awaitSession()).isEqualTo(session)
75+
}
76+
}
77+
78+
@Test
79+
fun `principal builder extension`() {
80+
val builder = mockk<ServerWebExchange.Builder>()
81+
val principal = mockk<Principal>()
82+
every { builder.principal(any<Mono<Principal>>()) } returns builder
83+
runBlocking {
84+
assertThat(builder.principal { principal }).isEqualTo(builder)
85+
}
86+
verify { builder.principal(any<Mono<Principal>>()) }
87+
}
88+
89+
}

spring-webflux/src/main/kotlin/org/springframework/web/reactive/server/ServerWebExchangeExtensions.kt

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2023 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.
@@ -31,6 +31,10 @@ import java.security.Principal
3131
* @author Sebastien Deleuze
3232
* @since 5.2
3333
*/
34+
@Deprecated(
35+
message = "Use the variant with the org.springframework.web.server package instead.",
36+
ReplaceWith("awaitFormData()", "org.springframework.web.server.awaitFormData"),
37+
)
3438
suspend fun ServerWebExchange.awaitFormData(): MultiValueMap<String, String> =
3539
this.formData.awaitSingle()
3640

@@ -40,6 +44,10 @@ suspend fun ServerWebExchange.awaitFormData(): MultiValueMap<String, String> =
4044
* @author Sebastien Deleuze
4145
* @since 5.2
4246
*/
47+
@Deprecated(
48+
message = "Use the variant with the org.springframework.web.server package instead.",
49+
ReplaceWith("awaitMultipartData()", "org.springframework.web.server.awaitMultipartData"),
50+
)
4351
suspend fun ServerWebExchange.awaitMultipartData(): MultiValueMap<String, Part> =
4452
this.multipartData.awaitSingle()
4553

@@ -49,6 +57,10 @@ suspend fun ServerWebExchange.awaitMultipartData(): MultiValueMap<String, Part>
4957
* @author Sebastien Deleuze
5058
* @since 5.2
5159
*/
60+
@Deprecated(
61+
message = "Use the variant with the org.springframework.web.server package instead.",
62+
ReplaceWith("awaitPrincipal<T>()", "org.springframework.web.server.awaitPrincipal"),
63+
)
5264
suspend fun <T : Principal> ServerWebExchange.awaitPrincipal(): T =
5365
this.getPrincipal<T>().awaitSingle()
5466

@@ -58,6 +70,10 @@ suspend fun <T : Principal> ServerWebExchange.awaitPrincipal(): T =
5870
* @author Sebastien Deleuze
5971
* @since 5.2
6072
*/
73+
@Deprecated(
74+
message = "Use the variant with the org.springframework.web.server package instead.",
75+
ReplaceWith("awaitSession()", "org.springframework.web.server.awaitSession"),
76+
)
6177
suspend fun ServerWebExchange.awaitSession(): WebSession =
6278
this.session.awaitSingle()
6379

@@ -67,5 +83,9 @@ suspend fun ServerWebExchange.awaitSession(): WebSession =
6783
* @author Sebastien Deleuze
6884
* @since 5.2
6985
*/
86+
@Deprecated(
87+
message = "Use the variant with the org.springframework.web.server package instead.",
88+
ReplaceWith("principal(supplier)", "org.springframework.web.server.principal"),
89+
)
7090
fun ServerWebExchange.Builder.principal(supplier: suspend () -> Principal): ServerWebExchange.Builder
7191
= principal(mono(Dispatchers.Unconfined) { supplier.invoke() })

0 commit comments

Comments
 (0)