16
16
17
17
package org.springframework.web.method.support
18
18
19
+ import kotlinx.coroutines.delay
19
20
import org.assertj.core.api.Assertions
20
21
import org.junit.jupiter.api.Test
22
+ import org.springframework.core.MethodParameter
21
23
import org.springframework.util.ReflectionUtils
24
+ import org.springframework.web.bind.support.WebDataBinderFactory
22
25
import org.springframework.web.context.request.NativeWebRequest
23
26
import org.springframework.web.context.request.ServletWebRequest
24
- import org.springframework.web.testfixture.method.ResolvableMethod
25
27
import org.springframework.web.testfixture.servlet.MockHttpServletRequest
26
28
import org.springframework.web.testfixture.servlet.MockHttpServletResponse
29
+ import reactor.core.publisher.Mono
30
+ import reactor.test.StepVerifier
27
31
import java.lang.reflect.Method
28
32
import kotlin.reflect.jvm.javaGetter
29
33
import kotlin.reflect.jvm.javaMethod
@@ -33,6 +37,7 @@ import kotlin.reflect.jvm.javaMethod
33
37
*
34
38
* @author Sebastien Deleuze
35
39
*/
40
+ @Suppress(" UNCHECKED_CAST" )
36
41
class InvocableHandlerMethodKotlinTests {
37
42
38
43
private val request: NativeWebRequest = ServletWebRequest (MockHttpServletRequest (), MockHttpServletResponse ())
@@ -110,6 +115,12 @@ class InvocableHandlerMethodKotlinTests {
110
115
Assertions .assertThat(value).isEqualTo(" foo" )
111
116
}
112
117
118
+ @Test
119
+ fun resultOfUnitReturnValue () {
120
+ val value = getInvocable(ValueClassHandler ::resultOfUnitReturnValue.javaMethod!! ).invokeForRequest(request, null )
121
+ Assertions .assertThat(value).isNull()
122
+ }
123
+
113
124
@Test
114
125
fun valueClassDefaultValue () {
115
126
composite.addResolver(StubArgumentResolver (Double ::class .java))
@@ -138,6 +149,60 @@ class InvocableHandlerMethodKotlinTests {
138
149
Assertions .assertThat(value).isEqualTo(' a' )
139
150
}
140
151
152
+ @Test
153
+ fun suspendingValueClass () {
154
+ composite.addResolver(ContinuationHandlerMethodArgumentResolver ())
155
+ composite.addResolver(StubArgumentResolver (Long ::class .java, 1L ))
156
+ val value = getInvocable(SuspendingValueClassHandler ::longValueClass.javaMethod!! ).invokeForRequest(request, null )
157
+ StepVerifier .create(value as Mono <Long >).expectNext(1L ).verifyComplete()
158
+ }
159
+
160
+ @Test
161
+ fun suspendingValueClassReturnValue () {
162
+ composite.addResolver(ContinuationHandlerMethodArgumentResolver ())
163
+ val value = getInvocable(SuspendingValueClassHandler ::valueClassReturnValue.javaMethod!! ).invokeForRequest(request, null )
164
+ StepVerifier .create(value as Mono <String >).expectNext(" foo" ).verifyComplete()
165
+ }
166
+
167
+ @Test
168
+ fun suspendingResultOfUnitReturnValue () {
169
+ composite.addResolver(ContinuationHandlerMethodArgumentResolver ())
170
+ val value = getInvocable(SuspendingValueClassHandler ::resultOfUnitReturnValue.javaMethod!! ).invokeForRequest(request, null )
171
+ StepVerifier .create(value as Mono <Unit >).verifyComplete()
172
+ }
173
+
174
+ @Test
175
+ fun suspendingValueClassDefaultValue () {
176
+ composite.addResolver(ContinuationHandlerMethodArgumentResolver ())
177
+ composite.addResolver(StubArgumentResolver (Double ::class .java))
178
+ val value = getInvocable(SuspendingValueClassHandler ::doubleValueClass.javaMethod!! ).invokeForRequest(request, null )
179
+ StepVerifier .create(value as Mono <Double >).expectNext(3.1 ).verifyComplete()
180
+ }
181
+
182
+ @Test
183
+ fun suspendingValueClassWithInit () {
184
+ composite.addResolver(ContinuationHandlerMethodArgumentResolver ())
185
+ composite.addResolver(StubArgumentResolver (String ::class .java, " " ))
186
+ val value = getInvocable(SuspendingValueClassHandler ::valueClassWithInit.javaMethod!! ).invokeForRequest(request, null )
187
+ StepVerifier .create(value as Mono <String >).verifyError(IllegalArgumentException ::class .java)
188
+ }
189
+
190
+ @Test
191
+ fun suspendingValueClassWithNullable () {
192
+ composite.addResolver(ContinuationHandlerMethodArgumentResolver ())
193
+ composite.addResolver(StubArgumentResolver (LongValueClass ::class .java, null ))
194
+ val value = getInvocable(SuspendingValueClassHandler ::valueClassWithNullable.javaMethod!! ).invokeForRequest(request, null )
195
+ StepVerifier .create(value as Mono <Long >).verifyComplete()
196
+ }
197
+
198
+ @Test
199
+ fun suspendingValueClassWithPrivateConstructor () {
200
+ composite.addResolver(ContinuationHandlerMethodArgumentResolver ())
201
+ composite.addResolver(StubArgumentResolver (Char ::class .java, ' a' ))
202
+ val value = getInvocable(SuspendingValueClassHandler ::valueClassWithPrivateConstructor.javaMethod!! ).invokeForRequest(request, null )
203
+ StepVerifier .create(value as Mono <Char >).expectNext(' a' ).verifyComplete()
204
+ }
205
+
141
206
@Test
142
207
fun propertyAccessor () {
143
208
val value = getInvocable(PropertyAccessorHandler ::prop.javaGetter!! ).invokeForRequest(request, null )
@@ -206,23 +271,58 @@ class InvocableHandlerMethodKotlinTests {
206
271
207
272
private class ValueClassHandler {
208
273
209
- fun valueClassReturnValue () =
210
- StringValueClass (" foo" )
274
+ fun valueClassReturnValue () = StringValueClass (" foo" )
275
+
276
+ fun resultOfUnitReturnValue () = Result .success(Unit )
277
+
278
+ fun longValueClass (limit : LongValueClass ) = limit.value
279
+
280
+ fun doubleValueClass (limit : DoubleValueClass = DoubleValueClass (3.1)) = limit.value
281
+
282
+ fun valueClassWithInit (valueClass : ValueClassWithInit ) = valueClass
283
+
284
+ fun valueClassWithNullable (limit : LongValueClass ? ) = limit?.value
285
+
286
+ fun valueClassWithPrivateConstructor (limit : ValueClassWithPrivateConstructor ) = limit.value
287
+ }
288
+
289
+ private class SuspendingValueClassHandler {
290
+
291
+ suspend fun valueClassReturnValue (): StringValueClass {
292
+ delay(1 )
293
+ return StringValueClass (" foo" )
294
+ }
295
+
296
+ suspend fun resultOfUnitReturnValue (): Result <Unit > {
297
+ delay(1 )
298
+ return Result .success(Unit )
299
+ }
211
300
212
- fun longValueClass (limit : LongValueClass ) =
213
- limit.value
301
+ suspend fun longValueClass (limit : LongValueClass ): Long {
302
+ delay(1 )
303
+ return limit.value
304
+ }
214
305
215
- fun doubleValueClass (limit : DoubleValueClass = DoubleValueClass (3.1)) =
216
- limit.value
217
306
218
- fun valueClassWithInit (valueClass : ValueClassWithInit ) =
219
- valueClass
307
+ suspend fun doubleValueClass (limit : DoubleValueClass = DoubleValueClass (3.1)): Double {
308
+ delay(1 )
309
+ return limit.value
310
+ }
220
311
221
- fun valueClassWithNullable (limit : LongValueClass ? ) =
222
- limit?.value
312
+ suspend fun valueClassWithInit (valueClass : ValueClassWithInit ): ValueClassWithInit {
313
+ delay(1 )
314
+ return valueClass
315
+ }
316
+
317
+ suspend fun valueClassWithNullable (limit : LongValueClass ? ): Long? {
318
+ delay(1 )
319
+ return limit?.value
320
+ }
223
321
224
- fun valueClassWithPrivateConstructor (limit : ValueClassWithPrivateConstructor ) =
225
- limit.value
322
+ suspend fun valueClassWithPrivateConstructor (limit : ValueClassWithPrivateConstructor ): Char {
323
+ delay(1 )
324
+ return limit.value
325
+ }
226
326
}
227
327
228
328
private class PropertyAccessorHandler {
@@ -282,4 +382,19 @@ class InvocableHandlerMethodKotlinTests {
282
382
283
383
class CustomException (message : String ) : Throwable(message)
284
384
385
+ // Avoid adding a spring-webmvc dependency
386
+ class ContinuationHandlerMethodArgumentResolver : HandlerMethodArgumentResolver {
387
+
388
+ override fun supportsParameter (parameter : MethodParameter ) =
389
+ " kotlin.coroutines.Continuation" == parameter.getParameterType().getName()
390
+
391
+ override fun resolveArgument (
392
+ parameter : MethodParameter ,
393
+ mavContainer : ModelAndViewContainer ? ,
394
+ webRequest : NativeWebRequest ,
395
+ binderFactory : WebDataBinderFactory ?
396
+ ) = null
397
+
398
+ }
399
+
285
400
}
0 commit comments