Skip to content

Commit

Permalink
Fix beginStructure in JsonTreeDecoder when inner structure descriptor…
Browse files Browse the repository at this point in the history
… is same as outer (#2346)

Instead of returning the same instance of decoder (with invalid position) a new instance is created, and polyDiscriminator and polyDescriptor are passed to the new instance.

This way check for unknown keys in endStructure can properly filter out polymorphic discriminator (by default "type) from potential unknown keys.

Fixes #2343
  • Loading branch information
ionspin committed Jun 29, 2023
1 parent fd75d35 commit 5bba108
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright 2017-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/

package kotlinx.serialization.json.polymorphic

import kotlinx.serialization.Serializable
import kotlinx.serialization.json.*
import kotlin.test.*

class JsonTreeDecoderPolymorphicTest : JsonTestBase() {

@Serializable
sealed class Sealed

@Serializable
data class ClassContainingItself(
val a: String,
val b: String,
val c: ClassContainingItself? = null,
val d: String?
) : Sealed()

val inner = ClassContainingItself(
"InnerA",
"InnerB",
null,
"InnerC"
)
val outer = ClassContainingItself(
"OuterA",
"OuterB",
inner,
"OuterC"
)

@Test
fun testDecodingWhenClassContainsItself() = parametrizedTest { jsonTestingMode ->
val encoded = default.encodeToString(outer as Sealed, jsonTestingMode)
val decoded: Sealed = Json.decodeFromString(encoded, jsonTestingMode)
assertEquals(outer, decoded)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ private sealed class AbstractJsonTreeDecoder(
@JvmField
protected val configuration = json.configuration

private fun currentObject() = currentTagOrNull?.let { currentElement(it) } ?: value
protected fun currentObject() = currentTagOrNull?.let { currentElement(it) } ?: value

override fun decodeJsonElement(): JsonElement = currentObject()

Expand Down Expand Up @@ -256,11 +256,14 @@ private open class JsonTreeDecoder(
override fun currentElement(tag: String): JsonElement = value.getValue(tag)

override fun beginStructure(descriptor: SerialDescriptor): CompositeDecoder {
/*
* For polymorphic serialization we'd like to avoid excessive decoder creating in
* beginStructure to properly preserve 'polyDiscriminator' field and filter it out.
*/
if (descriptor === polyDescriptor) return this
// polyDiscriminator needs to be preserved so the check for unknown keys
// in endStructure can filter polyDiscriminator out.
if (descriptor === polyDescriptor) {
return JsonTreeDecoder(
json, cast(currentObject(), polyDescriptor), polyDiscriminator, polyDescriptor
)
}

return super.beginStructure(descriptor)
}

Expand Down

0 comments on commit 5bba108

Please sign in to comment.