Browse Source

Make nullability flexible in ConverterFactory#getConverter

This commits udpates ConverterFactory#getConverter to accept both
nullable and non-null T in the Converter return value.

Flexible nullability at ConverterFactory type level would have been
ideal, but is not possible due to how Kotlin deals with Class<T> when
T is nullable.

See gh-36063
pull/36089/head
Sébastien Deleuze 1 month ago
parent
commit
96eee8c8b1
  1. 2
      spring-core/src/main/java/org/springframework/core/convert/converter/ConverterFactory.java
  2. 24
      spring-core/src/test/kotlin/org/springframework/core/convert/converter/ConverterFactoryNullnessTests.kt

2
spring-core/src/main/java/org/springframework/core/convert/converter/ConverterFactory.java

@ -38,6 +38,6 @@ public interface ConverterFactory<S, R> { @@ -38,6 +38,6 @@ public interface ConverterFactory<S, R> {
* @param targetType the target type to convert to
* @return a converter from S to T
*/
<T extends R> Converter<S, @Nullable T> getConverter(Class<T> targetType);
<T extends R> Converter<S, ? extends @Nullable T> getConverter(Class<T> targetType);
}

24
spring-core/src/test/kotlin/org/springframework/core/convert/converter/ConverterFactoryNullnessTests.kt

@ -22,18 +22,27 @@ import kotlin.reflect.full.primaryConstructor @@ -22,18 +22,27 @@ import kotlin.reflect.full.primaryConstructor
/**
* @author Brian Clozel
* @author Sebastien Deleuze
*/
class ConverterFactoryNullnessTests {
@Test
fun converterFactoryWithNullableTypes() {
val factory = StringToNullableIdConverterFactory
val userIdConverter: Converter<String, UserId?> = factory.getConverter(UserId::class.java)
assertThat(userIdConverter.convert("42")).isEqualTo(UserId("42"))
}
@Test
fun converterFactoryWithNonNullableTypes() {
val factory = StringToIdConverterFactory
val userIdConverter = factory.getConverter(UserId::class.java)
val userIdConverter: Converter<String, UserId> = factory.getConverter(UserId::class.java)
assertThat(userIdConverter.convert("42")).isEqualTo(UserId("42"))
}
object StringToIdConverterFactory : ConverterFactory<String, Id> {
object StringToNullableIdConverterFactory : ConverterFactory<String, Id> {
override fun <T : Id> getConverter(targetType: Class<T>): Converter<String, T?> {
val constructor = checkNotNull(targetType.kotlin.primaryConstructor)
return Converter { source ->
@ -42,12 +51,19 @@ class ConverterFactoryNullnessTests { @@ -42,12 +51,19 @@ class ConverterFactoryNullnessTests {
}
}
object StringToIdConverterFactory : ConverterFactory<String, Id> {
override fun <T : Id> getConverter(targetType: Class<T>): Converter<String, T> {
val constructor = checkNotNull(targetType.kotlin.primaryConstructor)
return Converter { source ->
constructor.call(source)
}
}
}
abstract class Id {
abstract val value: String
}
data class UserId(override val value: String) : Id()
data class ProductId(override val value: String) : Id()
}
Loading…
Cancel
Save