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