1 /*
<lambda>null2  * Copyright 2017-2020 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.reflect.*
10 
11 /**
12  * A builder which registers all its content for polymorphic serialization in the scope of the [base class][baseClass].
13  * If [baseSerializer] is present, registers it as a serializer for [baseClass] (which will be used if base class is serializable).
14  * Subclasses and its serializers can be added with [subclass] builder function.
15  *
16  * To obtain an instance of this builder, use [SerializersModuleBuilder.polymorphic] DSL function.
17  */
18 public class PolymorphicModuleBuilder<in Base : Any> @PublishedApi internal constructor(
19     private val baseClass: KClass<Base>,
20     private val baseSerializer: KSerializer<Base>? = null
21 ) {
22     private val subclasses: MutableList<Pair<KClass<out Base>, KSerializer<out Base>>> = mutableListOf()
23     private var defaultSerializerProvider: ((Base) -> SerializationStrategy<Base>?)? = null
24     private var defaultDeserializerProvider: ((String?) -> DeserializationStrategy<Base>?)? = null
25 
26     /**
27      * Registers a [subclass] [serializer] in the resulting module under the [base class][Base].
28      */
29     public fun <T : Base> subclass(subclass: KClass<T>, serializer: KSerializer<T>) {
30         subclasses.add(subclass to serializer)
31     }
32 
33     /**
34      * Adds a default serializers provider associated with the given [baseClass] to the resulting module.
35      * [defaultDeserializerProvider] is invoked when no polymorphic serializers associated with the `className`
36      * were found. `className` could be `null` for formats that support nullable class discriminators
37      * (currently only `Json` with `JsonBuilder.useArrayPolymorphism` set to `false`)
38      *
39      * Default deserializers provider affects only deserialization process. To affect serialization process, use
40      * [SerializersModuleBuilder.polymorphicDefaultSerializer].
41      *
42      * [defaultDeserializerProvider] can be stateful and lookup a serializer for the missing type dynamically.
43      *
44      * Typically, if the class is not registered in advance, it is not possible to know the structure of the unknown
45      * type and have a precise serializer, so the default serializer has limited capabilities.
46      * If you're using `Json` format, you can get a structural access to the unknown data using `JsonContentPolymorphicSerializer`.
47      *
48      * @see SerializersModuleBuilder.polymorphicDefaultSerializer
49      */
50     public fun defaultDeserializer(defaultDeserializerProvider: (className: String?) -> DeserializationStrategy<Base>?) {
51         require(this.defaultDeserializerProvider == null) {
52             "Default deserializer provider is already registered for class $baseClass: ${this.defaultDeserializerProvider}"
53         }
54         this.defaultDeserializerProvider = defaultDeserializerProvider
55     }
56 
57     /**
58      * Adds a default deserializers provider associated with the given [baseClass] to the resulting module.
59      * This function affect only deserialization process. To avoid confusion, it was deprecated and replaced with [defaultDeserializer].
60      * To affect serialization process, use [SerializersModuleBuilder.polymorphicDefaultSerializer].
61      *
62      * [defaultSerializerProvider] is invoked when no polymorphic serializers associated with the `className`
63      * were found. `className` could be `null` for formats that support nullable class discriminators
64      * (currently only `Json` with `JsonBuilder.useArrayPolymorphism` set to `false`)
65      *
66      * [defaultSerializerProvider] can be stateful and lookup a serializer for the missing type dynamically.
67      *
68      * Typically, if the class is not registered in advance, it is not possible to know the structure of the unknown
69      * type and have a precise serializer, so the default serializer has limited capabilities.
70      * If you're using `Json` format, you can get a structural access to the unknown data using `JsonContentPolymorphicSerializer`.
71      *
72      * @see defaultDeserializer
73      * @see SerializersModuleBuilder.polymorphicDefaultSerializer
74      */
75     @Deprecated(
76         "Deprecated in favor of function with more precise name: defaultDeserializer",
77         ReplaceWith("defaultDeserializer(defaultSerializerProvider)"),
78         DeprecationLevel.WARNING // Since 1.5.0. Raise to ERROR in 1.6.0, hide in 1.7.0
79     )
80     public fun default(defaultSerializerProvider: (className: String?) -> DeserializationStrategy<Base>?) {
81         defaultDeserializer(defaultSerializerProvider)
82     }
83 
84     @Suppress("UNCHECKED_CAST")
85     @PublishedApi
86     internal fun buildTo(builder: SerializersModuleBuilder) {
87         if (baseSerializer != null) builder.registerPolymorphicSerializer(baseClass, baseClass, baseSerializer)
88         subclasses.forEach { (kclass, serializer) ->
89             builder.registerPolymorphicSerializer(
90                 baseClass,
91                 kclass as KClass<Base>,
92                 serializer.cast()
93             )
94         }
95 
96         val defaultSerializer = defaultSerializerProvider
97         if (defaultSerializer != null) {
98             builder.registerDefaultPolymorphicSerializer(baseClass, defaultSerializer, false)
99         }
100 
101         val defaultDeserializer = defaultDeserializerProvider
102         if (defaultDeserializer != null) {
103             builder.registerDefaultPolymorphicDeserializer(baseClass, defaultDeserializer, false)
104         }
105     }
106 }
107 
108 /**
109  * Registers a [subclass] [serializer] in the resulting module under the [base class][Base].
110  */
subclassnull111 public inline fun <Base : Any, reified T : Base> PolymorphicModuleBuilder<Base>.subclass(serializer: KSerializer<T>): Unit =
112     subclass(T::class, serializer)
113 
114 /**
115  * Registers a serializer for class [T] in the resulting module under the [base class][Base].
116  */
117 public inline fun <Base : Any, reified T : Base> PolymorphicModuleBuilder<Base>.subclass(clazz: KClass<T>): Unit =
118     subclass(clazz, serializer())
119