Skip to content

Commit 95d5b4f

Browse files
authored
Make DeserializationStrategy covariant at declaration-site (#1897)
The type parameter T of DeserializationStrategy only appears in an out position, namely as the return type of deserialize(). It can therefore be annotated with `out` to increase API flexibility compared to DeserializationStrategy being invariant. E.g. a function taking DeserializationStrategy<Number> will now also accept an object of type DeserializationStrategy<Int>. This also results in DeserializationStrategy being more similar to the symmetric SerializationStrategy interface which is already contravariant at declaration-site (interface SerializationStrategy<in T>): SerializationStrategy is a consumer, and DeserializationStrategy is a producer. This change is * binary backward compatible: generics are erased at runtime * source backward compatible: previously specified out projections (use-site covariance) will only report a warning about a redundant projection
1 parent 46a5ff6 commit 95d5b4f

File tree

12 files changed

+19
-21
lines changed

12 files changed

+19
-21
lines changed

core/commonMain/src/kotlinx/serialization/KSerializer.kt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
package kotlinx.serialization
66

77
import kotlinx.serialization.descriptors.*
8-
import kotlinx.serialization.descriptors.elementNames
98
import kotlinx.serialization.encoding.*
109

1110
/**
@@ -140,7 +139,7 @@ public interface SerializationStrategy<in T> {
140139
*
141140
* For a more detailed explanation of the serialization process, please refer to [KSerializer] documentation.
142141
*/
143-
public interface DeserializationStrategy<T> {
142+
public interface DeserializationStrategy<out T> {
144143
/**
145144
* Describes the structure of the serializable representation of [T], that current
146145
* deserializer is able to deserialize.
@@ -193,4 +192,3 @@ public interface DeserializationStrategy<T> {
193192
*/
194193
public fun deserialize(decoder: Decoder): T
195194
}
196-

core/commonMain/src/kotlinx/serialization/PolymorphicSerializer.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ public class PolymorphicSerializer<T : Any>(override val baseClass: KClass<T>) :
9898
public fun <T : Any> AbstractPolymorphicSerializer<T>.findPolymorphicSerializer(
9999
decoder: CompositeDecoder,
100100
klassName: String?
101-
): DeserializationStrategy<out T> =
101+
): DeserializationStrategy<T> =
102102
findPolymorphicSerializerOrNull(decoder, klassName) ?: throwSubtypeNotRegistered(klassName, baseClass)
103103

104104
@InternalSerializationApi

core/commonMain/src/kotlinx/serialization/SealedSerializer.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ public class SealedClassSerializer<T : Any>(
137137
}.mapValues { it.value.value }
138138
}
139139

140-
override fun findPolymorphicSerializerOrNull(decoder: CompositeDecoder, klassName: String?): DeserializationStrategy<out T>? {
140+
override fun findPolymorphicSerializerOrNull(decoder: CompositeDecoder, klassName: String?): DeserializationStrategy<T>? {
141141
return serialName2Serializer[klassName] ?: super.findPolymorphicSerializerOrNull(decoder, klassName)
142142
}
143143

core/commonMain/src/kotlinx/serialization/internal/AbstractPolymorphicSerializer.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ public abstract class AbstractPolymorphicSerializer<T : Any> internal constructo
8181
public open fun findPolymorphicSerializerOrNull(
8282
decoder: CompositeDecoder,
8383
klassName: String?
84-
): DeserializationStrategy<out T>? = decoder.serializersModule.getPolymorphic(baseClass, klassName)
84+
): DeserializationStrategy<T>? = decoder.serializersModule.getPolymorphic(baseClass, klassName)
8585

8686

8787
/**

core/commonMain/src/kotlinx/serialization/modules/PolymorphicModuleBuilder.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public class PolymorphicModuleBuilder<in Base : Any> @PublishedApi internal cons
2121
) {
2222
private val subclasses: MutableList<Pair<KClass<out Base>, KSerializer<out Base>>> = mutableListOf()
2323
private var defaultSerializerProvider: ((Base) -> SerializationStrategy<Base>?)? = null
24-
private var defaultDeserializerProvider: ((String?) -> DeserializationStrategy<out Base>?)? = null
24+
private var defaultDeserializerProvider: ((String?) -> DeserializationStrategy<Base>?)? = null
2525

2626
/**
2727
* Registers a [subclass] [serializer] in the resulting module under the [base class][Base].
@@ -46,7 +46,7 @@ public class PolymorphicModuleBuilder<in Base : Any> @PublishedApi internal cons
4646
* Default deserializers provider affects only deserialization process.
4747
*/
4848
@ExperimentalSerializationApi
49-
public fun defaultDeserializer(defaultDeserializerProvider: (className: String?) -> DeserializationStrategy<out Base>?) {
49+
public fun defaultDeserializer(defaultDeserializerProvider: (className: String?) -> DeserializationStrategy<Base>?) {
5050
require(this.defaultDeserializerProvider == null) {
5151
"Default deserializer provider is already registered for class $baseClass: ${this.defaultDeserializerProvider}"
5252
}
@@ -75,7 +75,7 @@ public class PolymorphicModuleBuilder<in Base : Any> @PublishedApi internal cons
7575
*/
7676
@OptIn(ExperimentalSerializationApi::class)
7777
// TODO: deprecate in 1.4
78-
public fun default(defaultSerializerProvider: (className: String?) -> DeserializationStrategy<out Base>?) {
78+
public fun default(defaultSerializerProvider: (className: String?) -> DeserializationStrategy<Base>?) {
7979
defaultDeserializer(defaultSerializerProvider)
8080
}
8181

core/commonMain/src/kotlinx/serialization/modules/SerializersModule.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ public sealed class SerializersModule {
6161
* or default value constructed from [serializedClassName] if a default serializer provider was registered.
6262
*/
6363
@ExperimentalSerializationApi
64-
public abstract fun <T : Any> getPolymorphic(baseClass: KClass<in T>, serializedClassName: String?): DeserializationStrategy<out T>?
64+
public abstract fun <T : Any> getPolymorphic(baseClass: KClass<in T>, serializedClassName: String?): DeserializationStrategy<T>?
6565

6666
/**
6767
* Copies contents of this module to the given [collector].
@@ -129,7 +129,7 @@ public infix fun SerializersModule.overwriteWith(other: SerializersModule): Seri
129129

130130
override fun <Base : Any> polymorphicDefaultDeserializer(
131131
baseClass: KClass<Base>,
132-
defaultDeserializerProvider: (className: String?) -> DeserializationStrategy<out Base>?
132+
defaultDeserializerProvider: (className: String?) -> DeserializationStrategy<Base>?
133133
) {
134134
registerDefaultPolymorphicDeserializer(baseClass, defaultDeserializerProvider, allowOverwrite = true)
135135
}
@@ -161,7 +161,7 @@ internal class SerialModuleImpl(
161161
return (polyBase2DefaultSerializerProvider[baseClass] as? PolymorphicSerializerProvider<T>)?.invoke(value)
162162
}
163163

164-
override fun <T : Any> getPolymorphic(baseClass: KClass<in T>, serializedClassName: String?): DeserializationStrategy<out T>? {
164+
override fun <T : Any> getPolymorphic(baseClass: KClass<in T>, serializedClassName: String?): DeserializationStrategy<T>? {
165165
// Registered
166166
val registered = polyBase2NamedSerializers[baseClass]?.get(serializedClassName) as? KSerializer<out T>
167167
if (registered != null) return registered
@@ -204,7 +204,7 @@ internal class SerialModuleImpl(
204204
}
205205
}
206206

207-
internal typealias PolymorphicDeserializerProvider<Base> = (className: String?) -> DeserializationStrategy<out Base>?
207+
internal typealias PolymorphicDeserializerProvider<Base> = (className: String?) -> DeserializationStrategy<Base>?
208208
internal typealias PolymorphicSerializerProvider<Base> = (value: Base) -> SerializationStrategy<Base>?
209209

210210
/** This class is needed to support re-registering the same static (argless) serializers:

core/commonMain/src/kotlinx/serialization/modules/SerializersModuleBuilders.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ public class SerializersModuleBuilder @PublishedApi internal constructor() : Ser
122122
@ExperimentalSerializationApi
123123
public override fun <Base : Any> polymorphicDefaultDeserializer(
124124
baseClass: KClass<Base>,
125-
defaultDeserializerProvider: (className: String?) -> DeserializationStrategy<out Base>?
125+
defaultDeserializerProvider: (className: String?) -> DeserializationStrategy<Base>?
126126
) {
127127
registerDefaultPolymorphicDeserializer(baseClass, defaultDeserializerProvider, false)
128128
}
@@ -168,7 +168,7 @@ public class SerializersModuleBuilder @PublishedApi internal constructor() : Ser
168168
@JvmName("registerDefaultPolymorphicDeserializer") // Don't mangle method name for prettier stack traces
169169
internal fun <Base : Any> registerDefaultPolymorphicDeserializer(
170170
baseClass: KClass<Base>,
171-
defaultDeserializerProvider: (className: String?) -> DeserializationStrategy<out Base>?,
171+
defaultDeserializerProvider: (className: String?) -> DeserializationStrategy<Base>?,
172172
allowOverwrite: Boolean
173173
) {
174174
val previous = polyBase2DefaultDeserializerProvider[baseClass]

core/commonMain/src/kotlinx/serialization/modules/SerializersModuleCollector.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ public interface SerializersModuleCollector {
7070
@ExperimentalSerializationApi
7171
public fun <Base : Any> polymorphicDefaultDeserializer(
7272
baseClass: KClass<Base>,
73-
defaultDeserializerProvider: (className: String?) -> DeserializationStrategy<out Base>?
73+
defaultDeserializerProvider: (className: String?) -> DeserializationStrategy<Base>?
7474
)
7575

7676
/**
@@ -84,7 +84,7 @@ public interface SerializersModuleCollector {
8484
// TODO: deprecate in 1.4
8585
public fun <Base : Any> polymorphicDefault(
8686
baseClass: KClass<Base>,
87-
defaultDeserializerProvider: (className: String?) -> DeserializationStrategy<out Base>?
87+
defaultDeserializerProvider: (className: String?) -> DeserializationStrategy<Base>?
8888
) {
8989
polymorphicDefaultDeserializer(baseClass, defaultDeserializerProvider)
9090
}

formats/json/commonMain/src/kotlinx/serialization/json/JsonContentPolymorphicSerializer.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ public abstract class JsonContentPolymorphicSerializer<T : Any>(private val base
9696
/**
9797
* Determines a particular strategy for deserialization by looking on a parsed JSON [element].
9898
*/
99-
protected abstract fun selectDeserializer(element: JsonElement): DeserializationStrategy<out T>
99+
protected abstract fun selectDeserializer(element: JsonElement): DeserializationStrategy<T>
100100

101101
private fun throwSubtypeNotRegistered(subClass: KClass<*>, baseClass: KClass<*>): Nothing {
102102
val subClassName = subClass.simpleName ?: "$subClass"

formats/json/commonMain/src/kotlinx/serialization/json/internal/PolymorphismValidator.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ internal class PolymorphismValidator(
8383

8484
override fun <Base : Any> polymorphicDefaultDeserializer(
8585
baseClass: KClass<Base>,
86-
defaultDeserializerProvider: (className: String?) -> DeserializationStrategy<out Base>?
86+
defaultDeserializerProvider: (className: String?) -> DeserializationStrategy<Base>?
8787
) {
8888
// Nothing here
8989
}

0 commit comments

Comments
 (0)