• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * Copyright 2017-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3  */
4 
5 package kotlinx.serialization.modules
6 
7 import kotlinx.serialization.*
8 import kotlinx.serialization.internal.*
9 import kotlin.js.*
10 import kotlin.jvm.*
11 import kotlin.reflect.*
12 
13 /**
14  * [SerializersModule] is a collection of serializers used by [ContextualSerializer] and [PolymorphicSerializer]
15  * to override or provide serializers at the runtime, whereas at the compile-time they provided by the serialization plugin.
16  * It can be considered as a map where serializers can be found using their statically known KClasses.
17  *
18  * To enable runtime serializers resolution, one of the special annotations must be used on target types
19  * ([Polymorphic] or [Contextual]), and a serial module with serializers should be used during construction of [SerialFormat].
20  *
21  * Serializers module can be built with `SerializersModule {}` builder function.
22  * Empty module can be obtained with `EmptySerializersModule()` factory function.
23  *
24  * @see Contextual
25  * @see Polymorphic
26  */
27 public sealed class SerializersModule {
28 
29     @ExperimentalSerializationApi
30     @Deprecated(
31         "Deprecated in favor of overload with default parameter",
32         ReplaceWith("getContextual(kclass)"),
33         DeprecationLevel.HIDDEN
34     ) // Was experimental since 1.0.0, HIDDEN in 1.2.0 in a backwards-compatible manner
35     public fun <T : Any> getContextual(kclass: KClass<T>): KSerializer<T>? =
36         getContextual(kclass, emptyList())
37 
38     /**
39      * Returns a contextual serializer associated with a given [kClass].
40      * If given class has generic parameters and module has provider for [kClass],
41      * [typeArgumentsSerializers] are used to create serializer.
42      * This method is used in context-sensitive operations on a property marked with [Contextual] by a [ContextualSerializer].
43      *
44      * @see SerializersModuleBuilder.contextual
45      */
46     @ExperimentalSerializationApi
47     public abstract fun <T : Any> getContextual(
48         kClass: KClass<T>,
49         typeArgumentsSerializers: List<KSerializer<*>> = emptyList()
50     ): KSerializer<T>?
51 
52     /**
53      * Returns a polymorphic serializer registered for a class of the given [value] in the scope of [baseClass].
54      */
55     @ExperimentalSerializationApi
56     public abstract fun <T : Any> getPolymorphic(baseClass: KClass<in T>, value: T): SerializationStrategy<T>?
57 
58     /**
59      * Returns a polymorphic deserializer registered for a [serializedClassName] in the scope of [baseClass]
60      * or default value constructed from [serializedClassName] if a default serializer provider was registered.
61      */
62     @ExperimentalSerializationApi
63     public abstract fun <T : Any> getPolymorphic(baseClass: KClass<in T>, serializedClassName: String?): DeserializationStrategy<T>?
64 
65     /**
66      * Copies contents of this module to the given [collector].
67      */
68     @ExperimentalSerializationApi
69     public abstract fun dumpTo(collector: SerializersModuleCollector)
70 
71     @InternalSerializationApi
72     internal abstract val hasInterfaceContextualSerializers: Boolean
73 }
74 
75 /**
76  * A [SerializersModule] which is empty and always returns `null`.
77  */
78 @Deprecated("Deprecated in the favour of 'EmptySerializersModule()'",
79     level = DeprecationLevel.WARNING,
80     replaceWith = ReplaceWith("EmptySerializersModule()"))
81 @JsName("EmptySerializersModuleLegacyJs") // Compatibility with JS
82 public val EmptySerializersModule: SerializersModule = SerialModuleImpl(
83     emptyMap(),
84     emptyMap(),
85     emptyMap(),
86     emptyMap(),
87     emptyMap(),
88     false
89 )
90 
91 /**
92  * Returns a combination of two serial modules
93  *
94  * If serializer for some class presents in both modules, a [SerializerAlreadyRegisteredException] is thrown.
95  * To overwrite serializers, use [SerializersModule.overwriteWith] function.
96  */
<lambda>null97 public operator fun SerializersModule.plus(other: SerializersModule): SerializersModule = SerializersModule {
98     include(this@plus)
99     include(other)
100 }
101 
102 /**
103  * Returns a combination of two serial modules
104  *
105  * If serializer for some class presents in both modules, result module
106  * will contain serializer from [other] module.
107  */
108 @OptIn(ExperimentalSerializationApi::class)
<lambda>null109 public infix fun SerializersModule.overwriteWith(other: SerializersModule): SerializersModule = SerializersModule {
110     include(this@overwriteWith)
111     other.dumpTo(object : SerializersModuleCollector {
112         override fun <T : Any> contextual(kClass: KClass<T>, serializer: KSerializer<T>) {
113             registerSerializer(kClass, ContextualProvider.Argless(serializer), allowOverwrite = true)
114         }
115 
116         override fun <T : Any> contextual(
117             kClass: KClass<T>,
118             provider: (serializers: List<KSerializer<*>>) -> KSerializer<*>
119         ) {
120             registerSerializer(kClass, ContextualProvider.WithTypeArguments(provider), allowOverwrite = true)
121         }
122 
123         override fun <Base : Any, Sub : Base> polymorphic(
124             baseClass: KClass<Base>,
125             actualClass: KClass<Sub>,
126             actualSerializer: KSerializer<Sub>
127         ) {
128             registerPolymorphicSerializer(baseClass, actualClass, actualSerializer, allowOverwrite = true)
129         }
130 
131         override fun <Base : Any> polymorphicDefaultSerializer(
132             baseClass: KClass<Base>,
133             defaultSerializerProvider: (value: Base) -> SerializationStrategy<Base>?
134         ) {
135             registerDefaultPolymorphicSerializer(baseClass, defaultSerializerProvider, allowOverwrite = true)
136         }
137 
138         override fun <Base : Any> polymorphicDefaultDeserializer(
139             baseClass: KClass<Base>,
140             defaultDeserializerProvider: (className: String?) -> DeserializationStrategy<Base>?
141         ) {
142             registerDefaultPolymorphicDeserializer(baseClass, defaultDeserializerProvider, allowOverwrite = true)
143         }
144     })
145 }
146 
147 // Implementation details below
148 
149 /**
150  * A default implementation of [SerializersModule]
151  * which uses hash maps to store serializers associated with KClasses.
152  */
153 @Suppress("UNCHECKED_CAST")
154 @OptIn(ExperimentalSerializationApi::class)
155 internal class SerialModuleImpl(
156     private val class2ContextualFactory: Map<KClass<*>, ContextualProvider>,
157     @JvmField val polyBase2Serializers: Map<KClass<*>, Map<KClass<*>, KSerializer<*>>>,
158     private val polyBase2DefaultSerializerProvider: Map<KClass<*>, PolymorphicSerializerProvider<*>>,
159     private val polyBase2NamedSerializers: Map<KClass<*>, Map<String, KSerializer<*>>>,
160     private val polyBase2DefaultDeserializerProvider: Map<KClass<*>, PolymorphicDeserializerProvider<*>>,
161     internal override val hasInterfaceContextualSerializers: Boolean
162 ) : SerializersModule() {
163 
getPolymorphicnull164     override fun <T : Any> getPolymorphic(baseClass: KClass<in T>, value: T): SerializationStrategy<T>? {
165         if (!baseClass.isInstance(value)) return null
166         // Registered
167         val registered = polyBase2Serializers[baseClass]?.get(value::class) as? SerializationStrategy<T>
168         if (registered != null) return registered
169         // Default
170         return (polyBase2DefaultSerializerProvider[baseClass] as? PolymorphicSerializerProvider<T>)?.invoke(value)
171     }
172 
getPolymorphicnull173     override fun <T : Any> getPolymorphic(baseClass: KClass<in T>, serializedClassName: String?): DeserializationStrategy<T>? {
174         // Registered
175         val registered = polyBase2NamedSerializers[baseClass]?.get(serializedClassName) as? KSerializer<out T>
176         if (registered != null) return registered
177         // Default
178         return (polyBase2DefaultDeserializerProvider[baseClass] as? PolymorphicDeserializerProvider<T>)?.invoke(serializedClassName)
179     }
180 
getContextualnull181     override fun <T : Any> getContextual(kClass: KClass<T>, typeArgumentsSerializers: List<KSerializer<*>>): KSerializer<T>? {
182         return (class2ContextualFactory[kClass]?.invoke(typeArgumentsSerializers)) as? KSerializer<T>?
183     }
184 
dumpTonull185     override fun dumpTo(collector: SerializersModuleCollector) {
186         class2ContextualFactory.forEach { (kclass, serial) ->
187             when (serial) {
188                 is ContextualProvider.Argless -> collector.contextual(
189                     kclass as KClass<Any>,
190                     serial.serializer as KSerializer<Any>
191                 )
192                 is ContextualProvider.WithTypeArguments -> collector.contextual(kclass, serial.provider)
193             }
194         }
195 
196         polyBase2Serializers.forEach { (baseClass, classMap) ->
197             classMap.forEach { (actualClass, serializer) ->
198                 collector.polymorphic(
199                     baseClass as KClass<Any>,
200                     actualClass as KClass<Any>,
201                     serializer.cast()
202                 )
203             }
204         }
205 
206         polyBase2DefaultSerializerProvider.forEach { (baseClass, provider) ->
207             collector.polymorphicDefaultSerializer(baseClass as KClass<Any>, provider as (PolymorphicSerializerProvider<Any>))
208         }
209 
210         polyBase2DefaultDeserializerProvider.forEach { (baseClass, provider) ->
211             collector.polymorphicDefaultDeserializer(baseClass as KClass<Any>, provider as (PolymorphicDeserializerProvider<Any>))
212         }
213     }
214 }
215 
216 internal typealias PolymorphicDeserializerProvider<Base> = (className: String?) -> DeserializationStrategy<Base>?
217 internal typealias PolymorphicSerializerProvider<Base> = (value: Base) -> SerializationStrategy<Base>?
218 
219 /** This class is needed to support re-registering the same static (argless) serializers:
220  *
221  * ```
222  * val m1 = serializersModuleOf(A::class, A.serializer())
223  * val m2 = serializersModuleOf(A::class, A.serializer())
224  * val aggregate = m1 + m2 // should not throw
225  * ```
226  */
227 internal sealed class ContextualProvider {
invokenull228     abstract operator fun invoke(typeArgumentsSerializers: List<KSerializer<*>>): KSerializer<*>
229 
230     class Argless(val serializer: KSerializer<*>) : ContextualProvider() {
231         override fun invoke(typeArgumentsSerializers: List<KSerializer<*>>): KSerializer<*> = serializer
232 
233         override fun equals(other: Any?): Boolean = other is Argless && other.serializer == this.serializer
234 
235         override fun hashCode(): Int = serializer.hashCode()
236     }
237 
238     class WithTypeArguments(val provider: (typeArgumentsSerializers: List<KSerializer<*>>) -> KSerializer<*>) :
239         ContextualProvider() {
invokenull240         override fun invoke(typeArgumentsSerializers: List<KSerializer<*>>): KSerializer<*> =
241             provider(typeArgumentsSerializers)
242     }
243 
244 }
245