Skip to content

Commit b8de86f

Browse files
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 <[email protected]>
1 parent 782b9f3 commit b8de86f

File tree

3 files changed

+59
-2
lines changed

3 files changed

+59
-2
lines changed

core/commonTest/src/kotlinx/serialization/SerializersModuleTest.kt

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ class SerializersModuleTest {
3737
@Serializable
3838
class Parametrized<T : Any>(val a: T)
3939

40+
@Serializable
41+
class ParametrizedOfNullable<T>(val a: T)
42+
4043
class ContextualType(val i: Int)
4144

4245
@Serializer(forClass = ContextualType::class)
@@ -81,6 +84,27 @@ class SerializersModuleTest {
8184
assertEquals(PrimitiveKind.INT, mapSerializer.descriptor.getElementDescriptor(1).kind)
8285
}
8386

87+
@Suppress("UNCHECKED_CAST")
88+
@Test
89+
fun testNothingAndParameterizedOfNothing() {
90+
assertEquals(NothingSerializer, Nothing::class.serializer())
91+
//assertEquals(NothingSerializer, serializer<Nothing>()) // prohibited by compiler
92+
assertEquals(NothingSerializer, serializer(Nothing::class, emptyList(), false) as KSerializer<Nothing>)
93+
//assertEquals(NullableSerializer(NothingSerializer), serializer<Nothing?>()) // prohibited by compiler
94+
assertEquals(
95+
NullableSerializer(NothingSerializer),
96+
serializer(Nothing::class, emptyList(), true) as KSerializer<Nothing?>
97+
)
98+
99+
val parameterizedNothingSerializer = serializer<Parametrized<Nothing>>()
100+
val nothingDescriptor = parameterizedNothingSerializer.descriptor.getElementDescriptor(0)
101+
assertEquals(NothingSerialDescriptor, nothingDescriptor)
102+
103+
val parameterizedNullableNothingSerializer = serializer<ParametrizedOfNullable<Nothing?>>()
104+
val nullableNothingDescriptor = parameterizedNullableNothingSerializer.descriptor.getElementDescriptor(0)
105+
assertEquals(SerialDescriptorForNullable(NothingSerialDescriptor), nullableNothingDescriptor)
106+
}
107+
84108
@Test
85109
fun testUnsupportedArray() {
86110
assertFails {

core/jsMain/src/kotlinx/serialization/internal/Platform.kt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,12 @@ internal actual fun BooleanArray.getChecked(index: Int): Boolean {
1616
if (index !in indices) throw IndexOutOfBoundsException("Index $index out of bounds $indices")
1717
return get(index)
1818
}
19-
@Suppress("UNCHECKED_CAST")
19+
2020
internal actual fun <T : Any> KClass<T>.compiledSerializerImpl(): KSerializer<T>? =
21-
this.constructSerializerForGivenTypeArgs() ?: this.js.asDynamic().Companion?.serializer() as? KSerializer<T>
21+
this.constructSerializerForGivenTypeArgs() ?: (
22+
if (this === Nothing::class) NothingSerializer // Workaround for KT-51333
23+
else this.js.asDynamic().Companion?.serializer()
24+
) as? KSerializer<T>
2225

2326
internal actual fun <T> createCache(factory: (KClass<*>) -> KSerializer<T>?): SerializerCache<T> {
2427
return object: SerializerCache<T> {
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* Copyright 2017-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
package kotlinx.serialization.protobuf
6+
7+
import kotlinx.serialization.*
8+
import kotlinx.serialization.test.*
9+
import kotlin.test.*
10+
11+
class ProtobufNothingTest {
12+
@Serializable
13+
/*private*/ data class NullableNothingBox(val value: Nothing?) // `private` doesn't work on the JS legacy target
14+
15+
@Serializable
16+
private data class ParameterizedBox<T : Any>(val value: T?)
17+
18+
private inline fun <reified T> testConversion(data: T, expectedHexString: String) {
19+
val string = ProtoBuf.encodeToHexString(data).uppercase()
20+
assertEquals(expectedHexString, string)
21+
assertEquals(data, ProtoBuf.decodeFromHexString(string))
22+
}
23+
24+
@Test
25+
fun testNothing() {
26+
testConversion(NullableNothingBox(null), "")
27+
if (isJsLegacy()) return
28+
testConversion(ParameterizedBox(null), "")
29+
}
30+
}

0 commit comments

Comments
 (0)