Polish Kotlin nullable support
This commit polishes Kotlin nullable support by reusing MethodParameter#isOptional() instead of adding a new MethodParameter#isNullable() method, adds Kotlin tests and introduces Spring Web Reactive support. Issue: SPR-14165
This commit is contained in:
@@ -100,7 +100,7 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle
|
||||
if (namedValueInfo.defaultValue != null) {
|
||||
arg = resolveStringValue(namedValueInfo.defaultValue);
|
||||
}
|
||||
else if (namedValueInfo.required && !nestedParameter.isOptional() && !nestedParameter.isNullable()) {
|
||||
else if (namedValueInfo.required && !nestedParameter.isOptional()) {
|
||||
handleMissingValue(namedValueInfo.name, nestedParameter, webRequest);
|
||||
}
|
||||
arg = handleNullValue(namedValueInfo.name, arg, nestedParameter.getNestedParameterType());
|
||||
|
||||
@@ -0,0 +1,218 @@
|
||||
package org.springframework.web.method.annotation
|
||||
|
||||
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertNull
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.springframework.core.MethodParameter
|
||||
import org.springframework.core.annotation.SynthesizingMethodParameter
|
||||
import org.springframework.core.convert.support.DefaultConversionService
|
||||
import org.springframework.http.HttpMethod
|
||||
import org.springframework.http.MediaType
|
||||
import org.springframework.mock.web.test.MockHttpServletRequest
|
||||
import org.springframework.mock.web.test.MockHttpServletResponse
|
||||
import org.springframework.mock.web.test.MockMultipartFile
|
||||
import org.springframework.mock.web.test.MockMultipartHttpServletRequest
|
||||
import org.springframework.util.ReflectionUtils
|
||||
import org.springframework.web.bind.MissingServletRequestParameterException
|
||||
import org.springframework.web.bind.annotation.RequestParam
|
||||
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer
|
||||
import org.springframework.web.bind.support.DefaultDataBinderFactory
|
||||
import org.springframework.web.bind.support.WebDataBinderFactory
|
||||
import org.springframework.web.context.request.NativeWebRequest
|
||||
import org.springframework.web.context.request.ServletWebRequest
|
||||
import org.springframework.web.multipart.MultipartFile
|
||||
import org.springframework.web.multipart.support.MissingServletRequestPartException
|
||||
|
||||
/**
|
||||
* Kotlin test fixture for [RequestParamMethodArgumentResolver].
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
*/
|
||||
class RequestParamMethodArgumentResolverKotlinTests {
|
||||
|
||||
lateinit var resolver: RequestParamMethodArgumentResolver
|
||||
lateinit var webRequest: NativeWebRequest
|
||||
lateinit var binderFactory: WebDataBinderFactory
|
||||
lateinit var request: MockHttpServletRequest
|
||||
|
||||
lateinit var nullableParamRequired: MethodParameter
|
||||
lateinit var nullableParamNotRequired: MethodParameter
|
||||
lateinit var nonNullableParamRequired: MethodParameter
|
||||
lateinit var nonNullableParamNotRequired: MethodParameter
|
||||
|
||||
lateinit var nullableMultipartParamRequired: MethodParameter
|
||||
lateinit var nullableMultipartParamNotRequired: MethodParameter
|
||||
lateinit var nonNullableMultipartParamRequired: MethodParameter
|
||||
lateinit var nonNullableMultipartParamNotRequired: MethodParameter
|
||||
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
resolver = RequestParamMethodArgumentResolver(null, true)
|
||||
request = MockHttpServletRequest()
|
||||
val initializer = ConfigurableWebBindingInitializer()
|
||||
initializer.conversionService = DefaultConversionService()
|
||||
binderFactory = DefaultDataBinderFactory(initializer)
|
||||
webRequest = ServletWebRequest(request, MockHttpServletResponse())
|
||||
|
||||
val method = ReflectionUtils.findMethod(javaClass, "handle", String::class.java,
|
||||
String::class.java, String::class.java, String::class.java,
|
||||
MultipartFile::class.java, MultipartFile::class.java,
|
||||
MultipartFile::class.java, MultipartFile::class.java)
|
||||
|
||||
nullableParamRequired = SynthesizingMethodParameter(method, 0)
|
||||
nullableParamNotRequired = SynthesizingMethodParameter(method, 1)
|
||||
nonNullableParamRequired = SynthesizingMethodParameter(method, 2)
|
||||
nonNullableParamNotRequired = SynthesizingMethodParameter(method, 3)
|
||||
|
||||
nullableMultipartParamRequired = SynthesizingMethodParameter(method, 4)
|
||||
nullableMultipartParamNotRequired = SynthesizingMethodParameter(method, 5)
|
||||
nonNullableMultipartParamRequired = SynthesizingMethodParameter(method, 6)
|
||||
nonNullableMultipartParamNotRequired = SynthesizingMethodParameter(method, 7)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun resolveNullableRequiredWithParameter() {
|
||||
request.addParameter("name", "123")
|
||||
var result = resolver.resolveArgument(nullableParamRequired, null, webRequest, binderFactory)
|
||||
assertEquals("123", result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun resolveNullableRequiredWithoutParameter() {
|
||||
var result = resolver.resolveArgument(nullableParamRequired, null, webRequest, binderFactory)
|
||||
assertNull(result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun resolveNullableNotRequiredWithParameter() {
|
||||
request.addParameter("name", "123")
|
||||
var result = resolver.resolveArgument(nullableParamNotRequired, null, webRequest, binderFactory)
|
||||
assertEquals("123", result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun resolveNullableNotRequiredWithoutParameter() {
|
||||
var result = resolver.resolveArgument(nullableParamNotRequired, null, webRequest, binderFactory)
|
||||
assertNull(result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun resolveNonNullableRequiredWithParameter() {
|
||||
request.addParameter("name", "123")
|
||||
var result = resolver.resolveArgument(nonNullableParamRequired, null, webRequest, binderFactory)
|
||||
assertEquals("123", result)
|
||||
}
|
||||
|
||||
@Test(expected = MissingServletRequestParameterException::class)
|
||||
fun resolveNonNullableRequiredWithoutParameter() {
|
||||
resolver.resolveArgument(nonNullableParamRequired, null, webRequest, binderFactory)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun resolveNonNullableNotRequiredWithParameter() {
|
||||
request.addParameter("name", "123")
|
||||
var result = resolver.resolveArgument(nonNullableParamNotRequired, null, webRequest, binderFactory)
|
||||
assertEquals("123", result)
|
||||
}
|
||||
|
||||
@Test(expected = TypeCastException::class)
|
||||
fun resolveNonNullableNotRequiredWithoutParameter() {
|
||||
resolver.resolveArgument(nonNullableParamNotRequired, null, webRequest, binderFactory) as String
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun resolveNullableRequiredWithMultipartParameter() {
|
||||
val request = MockMultipartHttpServletRequest()
|
||||
val expected = MockMultipartFile("mfile", "Hello World".toByteArray())
|
||||
request.addFile(expected)
|
||||
webRequest = ServletWebRequest(request)
|
||||
|
||||
var result = resolver.resolveArgument(nullableMultipartParamRequired, null, webRequest, binderFactory)
|
||||
assertEquals(expected, result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun resolveNullableRequiredWithoutMultipartParameter() {
|
||||
request.method = HttpMethod.POST.name
|
||||
request.contentType = MediaType.MULTIPART_FORM_DATA_VALUE
|
||||
|
||||
var result = resolver.resolveArgument(nullableMultipartParamRequired, null, webRequest, binderFactory)
|
||||
assertNull(result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun resolveNullableNotRequiredWithMultipartParameter() {
|
||||
val request = MockMultipartHttpServletRequest()
|
||||
val expected = MockMultipartFile("mfile", "Hello World".toByteArray())
|
||||
request.addFile(expected)
|
||||
webRequest = ServletWebRequest(request)
|
||||
|
||||
var result = resolver.resolveArgument(nullableMultipartParamNotRequired, null, webRequest, binderFactory)
|
||||
assertEquals(expected, result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun resolveNullableNotRequiredWithoutMultipartParameter() {
|
||||
request.method = HttpMethod.POST.name
|
||||
request.contentType = MediaType.MULTIPART_FORM_DATA_VALUE
|
||||
|
||||
var result = resolver.resolveArgument(nullableMultipartParamNotRequired, null, webRequest, binderFactory)
|
||||
assertNull(result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun resolveNonNullableRequiredWithMultipartParameter() {
|
||||
val request = MockMultipartHttpServletRequest()
|
||||
val expected = MockMultipartFile("mfile", "Hello World".toByteArray())
|
||||
request.addFile(expected)
|
||||
webRequest = ServletWebRequest(request)
|
||||
|
||||
var result = resolver.resolveArgument(nonNullableMultipartParamRequired, null, webRequest, binderFactory)
|
||||
assertEquals(expected, result)
|
||||
}
|
||||
|
||||
@Test(expected = MissingServletRequestPartException::class)
|
||||
fun resolveNonNullableRequiredWithoutMultipartParameter() {
|
||||
request.method = HttpMethod.POST.name
|
||||
request.contentType = MediaType.MULTIPART_FORM_DATA_VALUE
|
||||
resolver.resolveArgument(nonNullableMultipartParamRequired, null, webRequest, binderFactory)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun resolveNonNullableNotRequiredWithMultipartParameter() {
|
||||
val request = MockMultipartHttpServletRequest()
|
||||
val expected = MockMultipartFile("mfile", "Hello World".toByteArray())
|
||||
request.addFile(expected)
|
||||
webRequest = ServletWebRequest(request)
|
||||
|
||||
var result = resolver.resolveArgument(nonNullableMultipartParamNotRequired, null, webRequest, binderFactory)
|
||||
assertEquals(expected, result)
|
||||
}
|
||||
|
||||
@Test(expected = TypeCastException::class)
|
||||
fun resolveNonNullableNotRequiredWithoutMultipartParameter() {
|
||||
request.method = HttpMethod.POST.name
|
||||
request.contentType = MediaType.MULTIPART_FORM_DATA_VALUE
|
||||
resolver.resolveArgument(nonNullableMultipartParamNotRequired, null, webRequest, binderFactory) as MultipartFile
|
||||
}
|
||||
|
||||
|
||||
@Suppress("unused_parameter")
|
||||
fun handle(
|
||||
@RequestParam("name") nullableParamRequired: String?,
|
||||
@RequestParam("name", required = false) nullableParamNotRequired: String?,
|
||||
@RequestParam("name") nonNullableParamRequired: String,
|
||||
@RequestParam("name", required = false) nonNullableParamNotRequired: String,
|
||||
|
||||
@RequestParam("mfile") nullableMultipartParamRequired: MultipartFile?,
|
||||
@RequestParam("mfile", required = false) nullableMultipartParamNotRequired: MultipartFile?,
|
||||
@RequestParam("mfile") nonNullableMultipartParamRequired: MultipartFile,
|
||||
@RequestParam("mfile", required = false) nonNullableMultipartParamNotRequired: MultipartFile) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user