@@ -66,9 +66,8 @@ public fun SerializersModule.serializer(type: KType): KSerializer<Any?> =
66
66
* Returns `null` if serializer cannot be created (provided [type] or its type argument is not serializable and is not registered in [this] module).
67
67
*/
68
68
@OptIn(ExperimentalSerializationApi ::class )
69
- public fun SerializersModule.serializerOrNull (type : KType ): KSerializer <Any ?>? {
70
- return serializerByKTypeImpl(type, failOnMissingTypeArgSerializer = false )
71
- }
69
+ public fun SerializersModule.serializerOrNull (type : KType ): KSerializer <Any ?>? =
70
+ serializerByKTypeImpl(type, failOnMissingTypeArgSerializer = false )
72
71
73
72
@OptIn(ExperimentalSerializationApi ::class )
74
73
private fun SerializersModule.serializerByKTypeImpl (
@@ -79,54 +78,47 @@ private fun SerializersModule.serializerByKTypeImpl(
79
78
val isNullable = type.isMarkedNullable
80
79
val typeArguments = type.arguments
81
80
.map { requireNotNull(it.type) { " Star projections in type arguments are not allowed, but had $type " } }
82
- val result: KSerializer <Any >? = when {
83
- typeArguments.isEmpty() -> rootClass.serializerOrNull() ? : getContextual(rootClass)
84
- else -> builtinSerializer(typeArguments, rootClass, failOnMissingTypeArgSerializer)
85
- }?.cast()
86
- return result?.nullable(isNullable)
87
- }
88
81
89
- @OptIn( ExperimentalSerializationApi :: class )
90
- private fun SerializersModule. builtinSerializer (
91
- typeArguments : List < KType >,
92
- rootClass : KClass < Any >,
93
- failOnMissingTypeArgSerializer : Boolean
94
- ): KSerializer < out Any > ? {
95
- val serializers = if (failOnMissingTypeArgSerializer)
96
- typeArguments.map(:: serializer)
97
- else {
98
- typeArguments.map { serializerOrNull(it) ? : return null }
82
+ val cachedSerializer = if (typeArguments.isEmpty()) {
83
+ findCachedSerializer(rootClass, isNullable)
84
+ } else {
85
+ val cachedResult = findParametrizedCachedSerializer( rootClass, typeArguments, isNullable)
86
+ if ( failOnMissingTypeArgSerializer) {
87
+ cachedResult.getOrNull()
88
+ } else {
89
+ // return null if error occurred - serializer for parameter(s) was not found
90
+ cachedResult.getOrElse { return null }
91
+ }
99
92
}
100
- // Array is not supported, see KT-32839
101
- return when (rootClass) {
102
- Collection ::class , List ::class , MutableList ::class , ArrayList ::class -> ArrayListSerializer (serializers[0 ])
103
- HashSet ::class -> HashSetSerializer (serializers[0 ])
104
- Set ::class , MutableSet ::class , LinkedHashSet ::class -> LinkedHashSetSerializer (serializers[0 ])
105
- HashMap ::class -> HashMapSerializer (serializers[0 ], serializers[1 ])
106
- Map ::class , MutableMap ::class , LinkedHashMap ::class -> LinkedHashMapSerializer (
107
- serializers[0 ],
108
- serializers[1 ]
93
+ cachedSerializer?.let { return it }
94
+
95
+ // slow path to find contextual serializers in serializers module
96
+ val contextualSerializer: KSerializer <out Any ?>? = if (typeArguments.isEmpty()) {
97
+ getContextual(rootClass)
98
+ } else {
99
+ val serializers = serializersForParameters(typeArguments, failOnMissingTypeArgSerializer) ? : return null
100
+ // first, we look among the built-in serializers, because the parameter could be contextual
101
+ rootClass.parametrizedSerializerOrNull(typeArguments, serializers) ? : getContextual(
102
+ rootClass,
103
+ serializers
109
104
)
110
- Map .Entry ::class -> MapEntrySerializer (serializers[0 ], serializers[1 ])
111
- Pair ::class -> PairSerializer (serializers[0 ], serializers[1 ])
112
- Triple ::class -> TripleSerializer (serializers[0 ], serializers[1 ], serializers[2 ])
113
- else -> {
114
- if (isReferenceArray(rootClass)) {
115
- return ArraySerializer <Any , Any ?>(typeArguments[0 ].classifier as KClass <Any >, serializers[0 ]).cast()
116
- }
117
- val args = serializers.toTypedArray()
118
- rootClass.constructSerializerForGivenTypeArgs(* args)
119
- ? : reflectiveOrContextual(rootClass, serializers)
120
- }
121
105
}
106
+ return contextualSerializer?.cast<Any >()?.nullable(isNullable)
122
107
}
123
108
124
- @OptIn(ExperimentalSerializationApi ::class )
125
- internal fun <T : Any > SerializersModule.reflectiveOrContextual (
126
- kClass : KClass <T >,
127
- typeArgumentsSerializers : List <KSerializer <Any ?>>
128
- ): KSerializer <T >? {
129
- return kClass.serializerOrNull() ? : getContextual(kClass, typeArgumentsSerializers)
109
+ /* *
110
+ * Returns null only if `failOnMissingTypeArgSerializer == false` and at least one parameter serializer not found.
111
+ */
112
+ internal fun SerializersModule.serializersForParameters (
113
+ typeArguments : List <KType >,
114
+ failOnMissingTypeArgSerializer : Boolean
115
+ ): List <KSerializer <Any ?>>? {
116
+ val serializers = if (failOnMissingTypeArgSerializer) {
117
+ typeArguments.map { serializer(it) }
118
+ } else {
119
+ typeArguments.map { serializerOrNull(it) ? : return null }
120
+ }
121
+ return serializers
130
122
}
131
123
132
124
/* *
@@ -179,6 +171,47 @@ public fun <T : Any> KClass<T>.serializer(): KSerializer<T> = serializerOrNull()
179
171
public fun <T : Any > KClass<T>.serializerOrNull (): KSerializer <T >? =
180
172
compiledSerializerImpl() ? : builtinSerializerOrNull()
181
173
174
+ internal fun KClass<Any>.parametrizedSerializerOrNull (
175
+ types : List <KType >,
176
+ serializers : List <KSerializer <Any ?>>
177
+ ): KSerializer <out Any >? {
178
+ // builtin first because some standard parametrized interfaces (e.g. Map) must use builtin serializer but not polymorphic
179
+ return builtinParametrizedSerializer(types, serializers) ? : compiledParametrizedSerializer(serializers)
180
+ }
181
+
182
+
183
+ private fun KClass<Any>.compiledParametrizedSerializer (serializers : List <KSerializer <Any ?>>): KSerializer <out Any >? {
184
+ return constructSerializerForGivenTypeArgs(* serializers.toTypedArray())
185
+ }
186
+
187
+ @OptIn(ExperimentalSerializationApi ::class )
188
+ private fun KClass<Any>.builtinParametrizedSerializer (
189
+ typeArguments : List <KType >,
190
+ serializers : List <KSerializer <Any ?>>,
191
+ ): KSerializer <out Any >? {
192
+ // Array is not supported, see KT-32839
193
+ return when (this ) {
194
+ Collection ::class , List ::class , MutableList ::class , ArrayList ::class -> ArrayListSerializer (serializers[0 ])
195
+ HashSet ::class -> HashSetSerializer (serializers[0 ])
196
+ Set ::class , MutableSet ::class , LinkedHashSet ::class -> LinkedHashSetSerializer (serializers[0 ])
197
+ HashMap ::class -> HashMapSerializer (serializers[0 ], serializers[1 ])
198
+ Map ::class , MutableMap ::class , LinkedHashMap ::class -> LinkedHashMapSerializer (
199
+ serializers[0 ],
200
+ serializers[1 ]
201
+ )
202
+ Map .Entry ::class -> MapEntrySerializer (serializers[0 ], serializers[1 ])
203
+ Pair ::class -> PairSerializer (serializers[0 ], serializers[1 ])
204
+ Triple ::class -> TripleSerializer (serializers[0 ], serializers[1 ], serializers[2 ])
205
+ else -> {
206
+ if (isReferenceArray(this )) {
207
+ ArraySerializer (typeArguments[0 ].classifier as KClass <Any >, serializers[0 ])
208
+ } else {
209
+ null
210
+ }
211
+ }
212
+ }
213
+ }
214
+
182
215
private fun <T : Any > KSerializer<T>.nullable (shouldBeNullable : Boolean ): KSerializer <T ?> {
183
216
if (shouldBeNullable) return nullable
184
217
return this as KSerializer <T ?>
0 commit comments