Skip to content

Commit

Permalink
Stabilize EmptySerializersModule (#1921)
Browse files Browse the repository at this point in the history
Fixes #1765
  • Loading branch information
qwwdfsad authored May 31, 2022
1 parent bf3269b commit 9e2e16e
Show file tree
Hide file tree
Showing 28 changed files with 177 additions and 93 deletions.
1 change: 1 addition & 0 deletions core/api/kotlinx-serialization-core.api
Original file line number Diff line number Diff line change
Expand Up @@ -1205,6 +1205,7 @@ public final class kotlinx/serialization/modules/SerializersModuleBuilder : kotl
}

public final class kotlinx/serialization/modules/SerializersModuleBuildersKt {
public static final fun EmptySerializersModule ()Lkotlinx/serialization/modules/SerializersModule;
public static final fun SerializersModule (Lkotlin/jvm/functions/Function1;)Lkotlinx/serialization/modules/SerializersModule;
public static final fun polymorphic (Lkotlinx/serialization/modules/SerializersModuleBuilder;Lkotlin/reflect/KClass;Lkotlinx/serialization/KSerializer;Lkotlin/jvm/functions/Function1;)V
public static synthetic fun polymorphic$default (Lkotlinx/serialization/modules/SerializersModuleBuilder;Lkotlin/reflect/KClass;Lkotlinx/serialization/KSerializer;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
Expand Down
9 changes: 6 additions & 3 deletions core/commonMain/src/kotlinx/serialization/Serializers.kt
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,15 @@ public inline fun <reified T> SerializersModule.serializer(): KSerializer<T> {
* @throws SerializationException if serializer cannot be created (provided [type] or its type argument is not serializable).
*/
@OptIn(ExperimentalSerializationApi::class)
public fun serializer(type: KType): KSerializer<Any?> = EmptySerializersModule.serializer(type)
public fun serializer(type: KType): KSerializer<Any?> = EmptySerializersModule().serializer(type)

/**
* Creates a serializer for the given [type].
* [type] argument can be obtained with experimental [typeOf] method.
* Returns `null` if serializer cannot be created (provided [type] or its type argument is not serializable).
*/
@OptIn(ExperimentalSerializationApi::class)
public fun serializerOrNull(type: KType): KSerializer<Any?>? = EmptySerializersModule.serializerOrNull(type)
public fun serializerOrNull(type: KType): KSerializer<Any?>? = EmptySerializersModule().serializerOrNull(type)

/**
* Attempts to create a serializer for the given [type] and fallbacks to [contextual][SerializersModule.getContextual]
Expand Down Expand Up @@ -122,7 +122,10 @@ private fun SerializersModule.builtinSerializer(
}

@OptIn(ExperimentalSerializationApi::class)
internal fun <T : Any> SerializersModule.reflectiveOrContextual(kClass: KClass<T>, typeArgumentsSerializers: List<KSerializer<Any?>>): KSerializer<T>? {
internal fun <T : Any> SerializersModule.reflectiveOrContextual(
kClass: KClass<T>,
typeArgumentsSerializers: List<KSerializer<Any?>>
): KSerializer<T>? {
return kClass.serializerOrNull() ?: getContextual(kClass, typeArgumentsSerializers)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import kotlinx.serialization.modules.*
*/
@OptIn(ExperimentalSerializationApi::class)
internal object NoOpEncoder : AbstractEncoder() {
override val serializersModule: SerializersModule = EmptySerializersModule
override val serializersModule: SerializersModule = EmptySerializersModule()

public override fun encodeValue(value: Any): Unit = Unit

Expand Down
4 changes: 2 additions & 2 deletions core/commonMain/src/kotlinx/serialization/internal/Tagged.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public abstract class TaggedEncoder<Tag : Any?> : Encoder, CompositeEncoder {
protected abstract fun SerialDescriptor.getTag(index: Int): Tag

override val serializersModule: SerializersModule
get() = EmptySerializersModule
get() = EmptySerializersModule()

// ---- API ----
protected open fun encodeTaggedValue(tag: Tag, value: Any): Unit =
Expand Down Expand Up @@ -177,7 +177,7 @@ public abstract class NamedValueEncoder : TaggedEncoder<String>() {
@InternalSerializationApi
public abstract class TaggedDecoder<Tag : Any?> : Decoder, CompositeDecoder {
override val serializersModule: SerializersModule
get() = EmptySerializersModule
get() = EmptySerializersModule()

protected abstract fun SerialDescriptor.getTag(index: Int): Tag

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package kotlinx.serialization.modules

import kotlinx.serialization.*
import kotlinx.serialization.internal.*
import kotlin.js.*
import kotlin.jvm.*
import kotlin.native.concurrent.*
import kotlin.reflect.*
Expand All @@ -18,6 +19,9 @@ import kotlin.reflect.*
* To enable runtime serializers resolution, one of the special annotations must be used on target types
* ([Polymorphic] or [Contextual]), and a serial module with serializers should be used during construction of [SerialFormat].
*
* Serializers module can be built with `SerializersModule {}` builder function.
* Empty module can be obtained with `EmptySerializersModule()` factory function.
*
* @see Contextual
* @see Polymorphic
*/
Expand All @@ -28,7 +32,7 @@ public sealed class SerializersModule {
"Deprecated in favor of overload with default parameter",
ReplaceWith("getContextual(kclass)"),
DeprecationLevel.HIDDEN
) // Was stable since 1.0.0, HIDDEN in 1.2.0 in a backwards-compatible manner
) // Was experimental since 1.0.0, HIDDEN in 1.2.0 in a backwards-compatible manner
public fun <T : Any> getContextual(kclass: KClass<T>): KSerializer<T>? =
getContextual(kclass, emptyList())

Expand Down Expand Up @@ -70,7 +74,10 @@ public sealed class SerializersModule {
* A [SerializersModule] which is empty and always returns `null`.
*/
@SharedImmutable
@ExperimentalSerializationApi
@Deprecated("Deprecated in the favour of 'EmptySerializersModule()'",
level = DeprecationLevel.WARNING,
replaceWith = ReplaceWith("EmptySerializersModule()"))
@JsName("EmptySerializersModuleLegacyJs") // Compatibility with JS
public val EmptySerializersModule: SerializersModule = SerialModuleImpl(emptyMap(), emptyMap(), emptyMap(), emptyMap(), emptyMap())

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ public inline fun SerializersModule(builderAction: SerializersModuleBuilder.() -
return builder.build()
}

/**
* A [SerializersModule] which is empty and returns `null` from each method.
*/
public fun EmptySerializersModule(): SerializersModule = @Suppress("DEPRECATION") EmptySerializersModule

/**
* A builder class for [SerializersModule] DSL. To create an instance of builder, use [SerializersModule] factory function.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class BasicTypesSerializationTest {

// KeyValue Input/Output
class KeyValueOutput(private val sb: StringBuilder) : AbstractEncoder() {
override val serializersModule: SerializersModule = EmptySerializersModule
override val serializersModule: SerializersModule = EmptySerializersModule()

override fun beginStructure(descriptor: SerialDescriptor): CompositeEncoder {
sb.append('{')
Expand Down Expand Up @@ -56,7 +56,7 @@ class BasicTypesSerializationTest {
}

class KeyValueInput(private val inp: Parser) : AbstractDecoder() {
override val serializersModule: SerializersModule = EmptySerializersModule
override val serializersModule: SerializersModule = EmptySerializersModule()

override fun beginStructure(descriptor: SerialDescriptor): CompositeDecoder {
inp.expectAfterWhiteSpace('{')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,8 @@ class CustomPropertyAccessorsTest {
*/



private class CommonStringDecoder(private val elementCount: Int) : AbstractDecoder() {
override val serializersModule: SerializersModule = EmptySerializersModule
override val serializersModule: SerializersModule = EmptySerializersModule()
private var elementIndex = 0

override fun decodeString(): String {
Expand Down
26 changes: 19 additions & 7 deletions core/jvmMain/src/kotlinx/serialization/SerializersJvm.kt
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import kotlin.reflect.*
* @throws SerializationException if serializer cannot be created (provided [type] or its type argument is not serializable).
*/
@ExperimentalSerializationApi
public fun serializer(type: Type): KSerializer<Any> = EmptySerializersModule.serializer(type)
public fun serializer(type: Type): KSerializer<Any> = EmptySerializersModule().serializer(type)

/**
* Reflectively constructs a serializer for the given reflective Java [type].
Expand All @@ -40,7 +40,7 @@ public fun serializer(type: Type): KSerializer<Any> = EmptySerializersModule.ser
* Returns `null` if serializer cannot be created (provided [type] or its type argument is not serializable).
*/
@ExperimentalSerializationApi
public fun serializerOrNull(type: Type): KSerializer<Any>? = EmptySerializersModule.serializerOrNull(type)
public fun serializerOrNull(type: Type): KSerializer<Any>? = EmptySerializersModule().serializerOrNull(type)

/**
* Retrieves serializer for the given reflective Java [type] using
Expand All @@ -56,7 +56,8 @@ public fun serializerOrNull(type: Type): KSerializer<Any>? = EmptySerializersMod
*/
@ExperimentalSerializationApi
public fun SerializersModule.serializer(type: Type): KSerializer<Any> =
serializerByJavaTypeImpl(type, failOnMissingTypeArgSerializer = true) ?: type.prettyClass().serializerNotRegistered()
serializerByJavaTypeImpl(type, failOnMissingTypeArgSerializer = true) ?: type.prettyClass()
.serializerNotRegistered()

/**
* Retrieves serializer for the given reflective Java [type] using
Expand All @@ -75,7 +76,10 @@ public fun SerializersModule.serializerOrNull(type: Type): KSerializer<Any>? =
serializerByJavaTypeImpl(type, failOnMissingTypeArgSerializer = false)

@OptIn(ExperimentalSerializationApi::class)
private fun SerializersModule.serializerByJavaTypeImpl(type: Type, failOnMissingTypeArgSerializer: Boolean = true): KSerializer<Any>? =
private fun SerializersModule.serializerByJavaTypeImpl(
type: Type,
failOnMissingTypeArgSerializer: Boolean = true
): KSerializer<Any>? =
when (type) {
is GenericArrayType -> {
genericArraySerializer(type, failOnMissingTypeArgSerializer)
Expand All @@ -85,7 +89,9 @@ private fun SerializersModule.serializerByJavaTypeImpl(type: Type, failOnMissing
val rootClass = (type.rawType as Class<*>)
val args = (type.actualTypeArguments)
val argsSerializers =
if (failOnMissingTypeArgSerializer) args.map { serializer(it) } else args.map { serializerOrNull(it) ?: return null }
if (failOnMissingTypeArgSerializer) args.map { serializer(it) } else args.map {
serializerOrNull(it) ?: return null
}
when {
Set::class.java.isAssignableFrom(rootClass) -> SetSerializer(argsSerializers[0]) as KSerializer<Any>
List::class.java.isAssignableFrom(rootClass) || Collection::class.java.isAssignableFrom(rootClass) -> ListSerializer(
Expand Down Expand Up @@ -122,7 +128,10 @@ private fun SerializersModule.serializerByJavaTypeImpl(type: Type, failOnMissing
}

@OptIn(ExperimentalSerializationApi::class)
private fun SerializersModule.typeSerializer(type: Class<*>, failOnMissingTypeArgSerializer: Boolean): KSerializer<Any>? {
private fun SerializersModule.typeSerializer(
type: Class<*>,
failOnMissingTypeArgSerializer: Boolean
): KSerializer<Any>? {
return if (type.isArray && !type.componentType.isPrimitive) {
val eType: Class<*> = type.componentType
val s = if (failOnMissingTypeArgSerializer) serializer(eType) else (serializerOrNull(eType) ?: return null)
Expand All @@ -134,7 +143,10 @@ private fun SerializersModule.typeSerializer(type: Class<*>, failOnMissingTypeAr
}

@OptIn(ExperimentalSerializationApi::class)
private fun <T : Any> SerializersModule.reflectiveOrContextual(jClass: Class<T>, typeArgumentsSerializers: List<KSerializer<Any?>>): KSerializer<T>? {
private fun <T : Any> SerializersModule.reflectiveOrContextual(
jClass: Class<T>,
typeArgumentsSerializers: List<KSerializer<Any?>>
): KSerializer<T>? {
jClass.constructSerializerForGivenTypeArgs(*typeArgumentsSerializers.toTypedArray())?.let { return it }
val kClass = jClass.kotlin
return kClass.builtinSerializerOrNull() ?: getContextual(kClass, typeArgumentsSerializers)
Expand Down
Loading

0 comments on commit 9e2e16e

Please sign in to comment.