diff options
author | Shreck Ye <ShreckYe@gmail.com> | 2023-07-12 20:58:30 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-07-12 14:58:30 +0200 |
commit | b8de86f0e351f1099d2afb03ff92e2ef6256cbc7 (patch) | |
tree | 6527b6c563ef694f145d08f083c3d85805ac2132 | |
parent | 782b9f3be9970e0fd36215a86bf7fdba9f2bfe83 (diff) | |
download | kotlinx.serialization-b8de86f0e351f1099d2afb03ff92e2ef6256cbc7.tar.gz |
Support Serializer for Nothing on the JS target (#2330)
Workaround for KT-51333: serialization of `Nothing` on the JS target and related tests
See also #932
Co-authored-by: Leonid Startsev <sandwwraith@users.noreply.github.com>
3 files changed, 59 insertions, 2 deletions
diff --git a/core/commonTest/src/kotlinx/serialization/SerializersModuleTest.kt b/core/commonTest/src/kotlinx/serialization/SerializersModuleTest.kt index 079792e6..db996a75 100644 --- a/core/commonTest/src/kotlinx/serialization/SerializersModuleTest.kt +++ b/core/commonTest/src/kotlinx/serialization/SerializersModuleTest.kt @@ -37,6 +37,9 @@ class SerializersModuleTest { @Serializable class Parametrized<T : Any>(val a: T) + @Serializable + class ParametrizedOfNullable<T>(val a: T) + class ContextualType(val i: Int) @Serializer(forClass = ContextualType::class) @@ -81,6 +84,27 @@ class SerializersModuleTest { assertEquals(PrimitiveKind.INT, mapSerializer.descriptor.getElementDescriptor(1).kind) } + @Suppress("UNCHECKED_CAST") + @Test + fun testNothingAndParameterizedOfNothing() { + assertEquals(NothingSerializer, Nothing::class.serializer()) + //assertEquals(NothingSerializer, serializer<Nothing>()) // prohibited by compiler + assertEquals(NothingSerializer, serializer(Nothing::class, emptyList(), false) as KSerializer<Nothing>) + //assertEquals(NullableSerializer(NothingSerializer), serializer<Nothing?>()) // prohibited by compiler + assertEquals( + NullableSerializer(NothingSerializer), + serializer(Nothing::class, emptyList(), true) as KSerializer<Nothing?> + ) + + val parameterizedNothingSerializer = serializer<Parametrized<Nothing>>() + val nothingDescriptor = parameterizedNothingSerializer.descriptor.getElementDescriptor(0) + assertEquals(NothingSerialDescriptor, nothingDescriptor) + + val parameterizedNullableNothingSerializer = serializer<ParametrizedOfNullable<Nothing?>>() + val nullableNothingDescriptor = parameterizedNullableNothingSerializer.descriptor.getElementDescriptor(0) + assertEquals(SerialDescriptorForNullable(NothingSerialDescriptor), nullableNothingDescriptor) + } + @Test fun testUnsupportedArray() { assertFails { diff --git a/core/jsMain/src/kotlinx/serialization/internal/Platform.kt b/core/jsMain/src/kotlinx/serialization/internal/Platform.kt index d2659fe4..6bd63391 100644 --- a/core/jsMain/src/kotlinx/serialization/internal/Platform.kt +++ b/core/jsMain/src/kotlinx/serialization/internal/Platform.kt @@ -16,9 +16,12 @@ internal actual fun BooleanArray.getChecked(index: Int): Boolean { if (index !in indices) throw IndexOutOfBoundsException("Index $index out of bounds $indices") return get(index) } -@Suppress("UNCHECKED_CAST") + internal actual fun <T : Any> KClass<T>.compiledSerializerImpl(): KSerializer<T>? = - this.constructSerializerForGivenTypeArgs() ?: this.js.asDynamic().Companion?.serializer() as? KSerializer<T> + this.constructSerializerForGivenTypeArgs() ?: ( + if (this === Nothing::class) NothingSerializer // Workaround for KT-51333 + else this.js.asDynamic().Companion?.serializer() + ) as? KSerializer<T> internal actual fun <T> createCache(factory: (KClass<*>) -> KSerializer<T>?): SerializerCache<T> { return object: SerializerCache<T> { diff --git a/formats/protobuf/commonTest/src/kotlinx/serialization/protobuf/ProtobufNothingTest.kt b/formats/protobuf/commonTest/src/kotlinx/serialization/protobuf/ProtobufNothingTest.kt new file mode 100644 index 00000000..9c97b5ec --- /dev/null +++ b/formats/protobuf/commonTest/src/kotlinx/serialization/protobuf/ProtobufNothingTest.kt @@ -0,0 +1,30 @@ +/* + * Copyright 2017-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + +package kotlinx.serialization.protobuf + +import kotlinx.serialization.* +import kotlinx.serialization.test.* +import kotlin.test.* + +class ProtobufNothingTest { + @Serializable + /*private*/ data class NullableNothingBox(val value: Nothing?) // `private` doesn't work on the JS legacy target + + @Serializable + private data class ParameterizedBox<T : Any>(val value: T?) + + private inline fun <reified T> testConversion(data: T, expectedHexString: String) { + val string = ProtoBuf.encodeToHexString(data).uppercase() + assertEquals(expectedHexString, string) + assertEquals(data, ProtoBuf.decodeFromHexString(string)) + } + + @Test + fun testNothing() { + testConversion(NullableNothingBox(null), "") + if (isJsLegacy()) return + testConversion(ParameterizedBox(null), "") + } +}
\ No newline at end of file |