Skip to content

Commit ef67bce

Browse files
recursive-rat4Pavel Vasin
and
Pavel Vasin
authored
KeyValueSerializer: Fix missing call to endStructure() (#2272)
The sequential decoding path was missing it. Use decodeStructure() to avoid this error. Co-authored-by: Pavel Vasin <git@vasin.nl>
1 parent 8007574 commit ef67bce

File tree

3 files changed

+39
-14
lines changed

3 files changed

+39
-14
lines changed

core/commonMain/src/kotlinx/serialization/internal/Tuples.kt

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,35 +33,33 @@ internal sealed class KeyValueSerializer<K, V, R>(
3333
structuredEncoder.endStructure(descriptor)
3434
}
3535

36-
override fun deserialize(decoder: Decoder): R {
37-
val composite = decoder.beginStructure(descriptor)
38-
if (composite.decodeSequentially()) {
39-
val key = composite.decodeSerializableElement(descriptor, 0, keySerializer)
40-
val value = composite.decodeSerializableElement(descriptor, 1, valueSerializer)
41-
return toResult(key, value)
36+
override fun deserialize(decoder: Decoder): R = decoder.decodeStructure(descriptor) {
37+
if (decodeSequentially()) {
38+
val key = decodeSerializableElement(descriptor, 0, keySerializer)
39+
val value = decodeSerializableElement(descriptor, 1, valueSerializer)
40+
return@decodeStructure toResult(key, value)
4241
}
4342

4443
var key: Any? = NULL
4544
var value: Any? = NULL
4645
mainLoop@ while (true) {
47-
when (val idx = composite.decodeElementIndex(descriptor)) {
46+
when (val idx = decodeElementIndex(descriptor)) {
4847
CompositeDecoder.DECODE_DONE -> {
4948
break@mainLoop
5049
}
5150
0 -> {
52-
key = composite.decodeSerializableElement(descriptor, 0, keySerializer)
51+
key = decodeSerializableElement(descriptor, 0, keySerializer)
5352
}
5453
1 -> {
55-
value = composite.decodeSerializableElement(descriptor, 1, valueSerializer)
54+
value = decodeSerializableElement(descriptor, 1, valueSerializer)
5655
}
5756
else -> throw SerializationException("Invalid index: $idx")
5857
}
5958
}
60-
composite.endStructure(descriptor)
6159
if (key === NULL) throw SerializationException("Element 'key' is missing")
6260
if (value === NULL) throw SerializationException("Element 'value' is missing")
6361
@Suppress("UNCHECKED_CAST")
64-
return toResult(key as K, value as V)
62+
return@decodeStructure toResult(key as K, value as V)
6563
}
6664
}
6765

core/commonTest/src/kotlinx/serialization/internal/DummySequentialDecoder.kt

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,17 @@ class DummySequentialDecoder(
2121
override fun decodeSequentially(): Boolean = true
2222
override fun decodeElementIndex(descriptor: SerialDescriptor): Int = throw Error("This method shouldn't be called in sequential mode")
2323

24-
override fun beginStructure(descriptor: SerialDescriptor): CompositeDecoder = this
25-
override fun endStructure(descriptor: SerialDescriptor): Unit = Unit
24+
var beginStructureCalled = 0
25+
var endStructureCalled = 0
26+
27+
override fun beginStructure(descriptor: SerialDescriptor): CompositeDecoder {
28+
++beginStructureCalled
29+
return this
30+
}
31+
override fun endStructure(descriptor: SerialDescriptor): Unit {
32+
++endStructureCalled
33+
return Unit
34+
}
2635

2736
override fun decodeInline(descriptor: SerialDescriptor): Decoder = notImplemented()
2837

@@ -51,6 +60,6 @@ class DummySequentialDecoder(
5160
override fun decodeStringElement(descriptor: SerialDescriptor, index: Int): String = notImplemented()
5261

5362
override fun decodeInlineElement(descriptor: SerialDescriptor, index: Int): Decoder = notImplemented()
54-
override fun <T : Any?> decodeSerializableElement(descriptor: SerialDescriptor, index: Int, deserializer: DeserializationStrategy<T>, previousValue: T?): T = notImplemented()
63+
override fun <T : Any?> decodeSerializableElement(descriptor: SerialDescriptor, index: Int, deserializer: DeserializationStrategy<T>, previousValue: T?): T = decodeSerializableValue(deserializer)
5564
override fun <T : Any> decodeNullableSerializableElement(descriptor: SerialDescriptor, index: Int, deserializer: DeserializationStrategy<T?>, previousValue: T?): T? = notImplemented()
5665
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/*
2+
* Copyright 2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
package kotlinx.serialization.internal
6+
7+
import kotlin.test.*
8+
import kotlinx.serialization.builtins.*
9+
10+
class TuplesTest {
11+
@Test
12+
fun testSequentialDecodingKeyValue() {
13+
val decoder = DummySequentialDecoder()
14+
val serializer = MapEntrySerializer(Unit.serializer(), Unit.serializer())
15+
serializer.deserialize(decoder)
16+
assertEquals(decoder.beginStructureCalled, decoder.endStructureCalled)
17+
}
18+
}

0 commit comments

Comments
 (0)