1 /*
2  * 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.internal
6 
7 import kotlinx.serialization.*
8 import kotlinx.serialization.encoding.*
9 import kotlin.jvm.*
10 import kotlin.reflect.*
11 
12 /**
13  * Base class for providing multiplatform polymorphic serialization.
14  *
15  * This class cannot be implemented by library users. To learn how to use it for your case,
16  * please refer to [PolymorphicSerializer] for interfaces/abstract classes and [SealedClassSerializer] for sealed classes.
17  *
18  * By default, without special support from [Encoder], polymorphic types are serialized as list with
19  * two elements: class [serial name][SerialDescriptor.serialName] (String) and the object itself.
20  * Serial name equals to fully-qualified class name by default and can be changed via @[SerialName] annotation.
21  */
22 @InternalSerializationApi
23 @OptIn(ExperimentalSerializationApi::class)
24 public abstract class AbstractPolymorphicSerializer<T : Any> internal constructor() : KSerializer<T> {
25 
26     /**
27      * Base class for all classes that this polymorphic serializer can serialize or deserialize.
28      */
29     public abstract val baseClass: KClass<T>
30 
serializenull31     public final override fun serialize(encoder: Encoder, value: T) {
32         val actualSerializer = findPolymorphicSerializer(encoder, value)
33         encoder.encodeStructure(descriptor) {
34             encodeStringElement(descriptor, 0, actualSerializer.descriptor.serialName)
35             encodeSerializableElement(descriptor, 1, actualSerializer.cast(), value)
36         }
37     }
38 
<lambda>null39     public final override fun deserialize(decoder: Decoder): T = decoder.decodeStructure(descriptor) {
40         var klassName: String? = null
41         var value: Any? = null
42         if (decodeSequentially()) {
43             return@decodeStructure decodeSequentially(this)
44         }
45 
46         mainLoop@ while (true) {
47             when (val index = decodeElementIndex(descriptor)) {
48                 CompositeDecoder.DECODE_DONE -> {
49                     break@mainLoop
50                 }
51                 0 -> {
52                     klassName = decodeStringElement(descriptor, index)
53                 }
54                 1 -> {
55                     klassName = requireNotNull(klassName) { "Cannot read polymorphic value before its type token" }
56                     val serializer = findPolymorphicSerializer(this, klassName)
57                     value = decodeSerializableElement(descriptor, index, serializer)
58                 }
59                 else -> throw SerializationException(
60                     "Invalid index in polymorphic deserialization of " +
61                         (klassName ?: "unknown class") +
62                         "\n Expected 0, 1 or DECODE_DONE(-1), but found $index"
63                 )
64             }
65         }
66         @Suppress("UNCHECKED_CAST")
67         requireNotNull(value) { "Polymorphic value has not been read for class $klassName" } as T
68     }
69 
decodeSequentiallynull70     private fun decodeSequentially(compositeDecoder: CompositeDecoder): T {
71         val klassName = compositeDecoder.decodeStringElement(descriptor, 0)
72         val serializer = findPolymorphicSerializer(compositeDecoder, klassName)
73         return compositeDecoder.decodeSerializableElement(descriptor, 1, serializer)
74     }
75 
76     /**
77      * Lookups an actual serializer for given [klassName] withing the current [base class][baseClass].
78      * May use context from the [decoder].
79      */
80     @InternalSerializationApi
findPolymorphicSerializerOrNullnull81     public open fun findPolymorphicSerializerOrNull(
82         decoder: CompositeDecoder,
83         klassName: String?
84     ): DeserializationStrategy<T>? = decoder.serializersModule.getPolymorphic(baseClass, klassName)
85 
86 
87     /**
88      * Lookups an actual serializer for given [value] within the current [base class][baseClass].
89      * May use context from the [encoder].
90      */
91     @InternalSerializationApi
92     public open fun findPolymorphicSerializerOrNull(
93         encoder: Encoder,
94         value: T
95     ): SerializationStrategy<T>? =
96         encoder.serializersModule.getPolymorphic(baseClass, value)
97 }
98 
99 @JvmName("throwSubtypeNotRegistered")
100 internal fun throwSubtypeNotRegistered(subClassName: String?, baseClass: KClass<*>): Nothing {
101     val scope = "in the polymorphic scope of '${baseClass.simpleName}'"
102     throw SerializationException(
103         if (subClassName == null)
104             "Class discriminator was missing and no default serializers were registered $scope."
105         else
106             "Serializer for subclass '$subClassName' is not found $scope.\n" +
107                 "Check if class with serial name '$subClassName' exists and serializer is registered in a corresponding SerializersModule.\n" +
108                 "To be registered automatically, class '$subClassName' has to be '@Serializable', and the base class '${baseClass.simpleName}' has to be sealed and '@Serializable'."
109     )
110 }
111 
112 @JvmName("throwSubtypeNotRegistered")
throwSubtypeNotRegisterednull113 internal fun throwSubtypeNotRegistered(subClass: KClass<*>, baseClass: KClass<*>): Nothing =
114     throwSubtypeNotRegistered(subClass.simpleName ?: "$subClass", baseClass)
115