summaryrefslogtreecommitdiff
path: root/runtime/commonMain/src/kotlinx/serialization/modules/SerialModuleBuilders.kt
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/commonMain/src/kotlinx/serialization/modules/SerialModuleBuilders.kt')
-rw-r--r--runtime/commonMain/src/kotlinx/serialization/modules/SerialModuleBuilders.kt154
1 files changed, 154 insertions, 0 deletions
diff --git a/runtime/commonMain/src/kotlinx/serialization/modules/SerialModuleBuilders.kt b/runtime/commonMain/src/kotlinx/serialization/modules/SerialModuleBuilders.kt
new file mode 100644
index 00000000..20f28072
--- /dev/null
+++ b/runtime/commonMain/src/kotlinx/serialization/modules/SerialModuleBuilders.kt
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2017-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+@file:Suppress("RedundantVisibilityModifier")
+
+package kotlinx.serialization.modules
+
+import kotlinx.serialization.*
+import kotlin.jvm.JvmField
+import kotlin.reflect.KClass
+
+/**
+ * Returns a [SerialModule] which has one class with one serializer for [ContextSerializer].
+ */
+public fun <T : Any> serializersModuleOf(kClass: KClass<T>, serializer: KSerializer<T>): SerialModule =
+ SerializersModule { contextual(kClass, serializer) }
+
+/**
+ * Shortcut for [serializersModuleOf] function with type parameter.
+ */
+// it could be named `serializersModuleOf`, too, but https://youtrack.jetbrains.com/issue/KT-30176.
+public inline fun <reified T : Any> serializersModule(serializer: KSerializer<T>): SerialModule =
+ serializersModuleOf(T::class, serializer)
+
+/**
+ * Returns a [SerialModule] which has multiple classes with its serializers for [ContextSerializer].
+ */
+@Suppress("UNCHECKED_CAST")
+public fun serializersModuleOf(map: Map<KClass<*>, KSerializer<*>>): SerialModule = SerializersModule {
+ map.forEach { (kclass, serializer) -> contextual(kclass as KClass<Any>, serializer as KSerializer<Any>) }
+}
+
+
+/**
+ * A builder function for creating a [SerialModule].
+ *
+ * Serializers can be add via [SerializersModuleBuilder.contextual] or [SerializersModuleBuilder.polymorphic].
+ *
+ * Since [SerializersModuleBuilder] also implements [SerialModuleCollector], it is possible to copy whole another module to this builder with [SerialModule.dumpTo]
+ */
+@Suppress("FunctionName")
+public fun SerializersModule(buildAction: SerializersModuleBuilder.() -> Unit): SerialModule {
+ val builder = SerializersModuleBuilder(SerialModuleImpl())
+ builder.buildAction()
+ return builder.impl
+}
+
+/**
+ * A builder class for [SerializersModule] DSL.
+ */
+public class SerializersModuleBuilder internal constructor(@JvmField internal val impl: SerialModuleImpl) :
+ SerialModuleCollector {
+
+ /**
+ * Adds [serializer] associated with given [kClass] for contextual serialization.
+ * Throws [SerializationException] if a module already has serializer associated with a [kClass].
+ * To overwrite an already registered serializer, [SerialModule.overwriteWith] can be used.
+ */
+ public override fun <T : Any> contextual(kClass: KClass<T>, serializer: KSerializer<T>) = impl.registerSerializer(kClass, serializer)
+
+ /**
+ * Adds [serializer][actualSerializer] associated with given [actualClass] in the scope of [baseClass] for polymorphic serialization.
+ * Throws [SerializationException] if a module already has serializer associated with a [actualClass].
+ * To overwrite an already registered serializer, [SerialModule.overwriteWith] can be used.
+ */
+ public override fun <Base : Any, Sub : Base> polymorphic(
+ baseClass: KClass<Base>,
+ actualClass: KClass<Sub>,
+ actualSerializer: KSerializer<Sub>
+ ) {
+ impl.registerPolymorphicSerializer(baseClass, actualClass, actualSerializer)
+ }
+
+ /**
+ * Copies contents of [other] module into current builder.
+ */
+ public fun include(other: SerialModule) {
+ other.dumpTo(this)
+ }
+
+ /**
+ * Creates a builder to register all subclasses of a given [baseClass]
+ * for polymorphic serialization. If [baseSerializer] is not null, registers it as a serializer for [baseClass]
+ * (which is useful if base class is serializable). To add subclasses, use
+ * [PolymorphicModuleBuilder.addSubclass] or [PolymorphicModuleBuilder.with].
+ *
+ * If serializer already registered for the given KClass in the given scope, a [SerializerAlreadyRegisteredException] is thrown.
+ * To override registered serializers, combine built module with another using
+ * [SerialModule.overwriteWith].
+ *
+ * @see PolymorphicSerializer
+ */
+ public fun <Base : Any> polymorphic(
+ baseClass: KClass<Base>,
+ baseSerializer: KSerializer<Base>? = null,
+ buildAction: PolymorphicModuleBuilder<Base>.() -> Unit = {}
+ ) {
+ val builder = PolymorphicModuleBuilder(baseClass, baseSerializer)
+ builder.buildAction()
+ builder.buildTo(impl)
+ }
+
+ public inline fun <reified Base : Any> polymorphic(
+ baseSerializer: KSerializer<Base>? = null,
+ noinline buildAction: PolymorphicModuleBuilder<Base>.() -> Unit = {}
+ ) = polymorphic(Base::class, baseSerializer, buildAction)
+
+ /**
+ * Creates a builder to register all serializable subclasses for polymorphic serialization
+ * for multiple base classes. This is useful when you have more two or more super classes in a large hierarchy, e.g.:
+ *
+ * ```
+ * interface I
+ * @Serializable abstract class A() : I
+ * @Serializable final class B : A()
+ * @Serializable class Message(@Polymorphic val i: I, @Polymorphic val a: A)
+ * ```
+ *
+ * In this case, you have to register B as subclass for two base classes: I and A.
+ *
+ * Note that serializer (if present) for each of the [baseClasses] should be
+ * registered separately inside [buildAction] to avoid duplicates, e.g.:
+ *
+ * ```
+ * polymorphic(Any::class, PolyBase::class) {
+ * PolyBase::class with PolyBase.serializer()
+ * PolyDerived::class with PolyDerived.serializer()
+ * }
+ * ```
+ *
+ * If serializer already registered for the given KClass in the given scope, a [SerializerAlreadyRegisteredException] is thrown.
+ * To override registered serializers, combine built module with another using
+ * [SerialModule.overwriteWith].
+ *
+ * @see PolymorphicSerializer
+ */
+ @Suppress("UNCHECKED_CAST")
+ public fun polymorphic(
+ baseClass: KClass<*>,
+ vararg baseClasses: KClass<*>,
+ buildAction: PolymorphicModuleBuilder<Any>.() -> Unit = {}
+ ) {
+ val builder = PolymorphicModuleBuilder(baseClass as KClass<Any>, null)
+ builder.buildAction()
+ builder.buildTo(impl)
+ for (base in baseClasses) {
+ builder.changeBase(base as KClass<Any>, null).buildTo(impl)
+ }
+ }
+}
+
+@Deprecated(deprecationText, ReplaceWith("serializersModuleOf"))
+typealias SimpleModule<@Suppress("UNUSED_TYPEALIAS_PARAMETER") T> = SerialModule