commonMain.kotlinx.serialization.PolymorphicSerializer.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of kotlinx-serialization-core-jvm Show documentation
Show all versions of kotlinx-serialization-core-jvm Show documentation
Kotlin multiplatform serialization runtime library
The newest version!
/*
* Copyright 2017-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.serialization
import kotlinx.serialization.builtins.*
import kotlinx.serialization.descriptors.*
import kotlinx.serialization.encoding.*
import kotlinx.serialization.internal.*
import kotlinx.serialization.modules.*
import kotlin.reflect.*
/**
* This class provides support for multiplatform polymorphic serialization for interfaces and abstract classes.
*
* To avoid the most common security pitfalls and reflective lookup (and potential load) of an arbitrary class,
* all serializable implementations of any polymorphic type must be [registered][SerializersModuleBuilder.polymorphic]
* in advance in the scope of base polymorphic type, efficiently preventing unbounded polymorphic serialization
* of an arbitrary type.
*
* Polymorphic serialization is enabled automatically by default for interfaces and [Serializable] abstract classes.
* To enable this feature explicitly on other types, use `@SerializableWith(PolymorphicSerializer::class)`
* or [Polymorphic] annotation on the property.
*
* Usage of the polymorphic serialization can be demonstrated by the following example:
* ```
* abstract class BaseRequest()
* @Serializable
* data class RequestA(val id: Int): BaseRequest()
* @Serializable
* data class RequestB(val s: String): BaseRequest()
*
* abstract class BaseResponse()
* @Serializable
* data class ResponseC(val payload: Long): BaseResponse()
* @Serializable
* data class ResponseD(val payload: ByteArray): BaseResponse()
*
* @Serializable
* data class Message(
* @Polymorphic val request: BaseRequest,
* @Polymorphic val response: BaseResponse
* )
* ```
* In this example, both request and response in `Message` are serializable with [PolymorphicSerializer].
*
* `BaseRequest` and `BaseResponse` are base classes and they are captured during compile time by the plugin.
* Yet [PolymorphicSerializer] for `BaseRequest` should only allow `RequestA` and `RequestB` serializers, and none of the response's serializers.
*
* This is achieved via special registration function in the module:
* ```
* val requestAndResponseModule = SerializersModule {
* polymorphic(BaseRequest::class) {
* subclass(RequestA::class)
* subclass(RequestB::class)
* }
* polymorphic(BaseResponse::class) {
* subclass(ResponseC::class)
* subclass(ResponseD::class)
* }
* }
* ```
*
* @see SerializersModule
* @see SerializersModuleBuilder.polymorphic
*/
@OptIn(ExperimentalSerializationApi::class)
public class PolymorphicSerializer(override val baseClass: KClass) : AbstractPolymorphicSerializer() {
@PublishedApi // See comment in SealedClassSerializer
internal constructor(
baseClass: KClass,
classAnnotations: Array
) : this(baseClass) {
_annotations = classAnnotations.asList()
}
private var _annotations: List = emptyList()
public override val descriptor: SerialDescriptor by lazy(LazyThreadSafetyMode.PUBLICATION) {
buildSerialDescriptor("kotlinx.serialization.Polymorphic", PolymorphicKind.OPEN) {
element("type", String.serializer().descriptor)
element(
"value",
buildSerialDescriptor("kotlinx.serialization.Polymorphic<${baseClass.simpleName}>", SerialKind.CONTEXTUAL)
)
annotations = _annotations
}.withContext(baseClass)
}
override fun toString(): String {
return "kotlinx.serialization.PolymorphicSerializer(baseClass: $baseClass)"
}
}
@InternalSerializationApi
public fun AbstractPolymorphicSerializer.findPolymorphicSerializer(
decoder: CompositeDecoder,
klassName: String?
): DeserializationStrategy =
findPolymorphicSerializerOrNull(decoder, klassName) ?: throwSubtypeNotRegistered(klassName, baseClass)
@InternalSerializationApi
public fun AbstractPolymorphicSerializer.findPolymorphicSerializer(
encoder: Encoder,
value: T
): SerializationStrategy =
findPolymorphicSerializerOrNull(encoder, value) ?: throwSubtypeNotRegistered(value::class, baseClass)
© 2015 - 2025 Weber Informatics LLC | Privacy Policy