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