summaryrefslogtreecommitdiff
path: root/formats/json-tests/commonTest/src/kotlinx/serialization/features/PolymorphismWithAnyTest.kt
diff options
context:
space:
mode:
authorLeonid Startsev <sandwwraith@users.noreply.github.com>2023-10-19 18:16:43 +0200
committerGitHub <noreply@github.com>2023-10-19 18:16:43 +0200
commit7d4bb2a80b5ad7f053c8bd5596f7acb33e262114 (patch)
tree8a9730d886b52d082ebd0c66b57c5b19f84bc499 /formats/json-tests/commonTest/src/kotlinx/serialization/features/PolymorphismWithAnyTest.kt
parentcf57414d83314bf05cb28ae8a600163b96855ba0 (diff)
downloadkotlinx.serialization-7d4bb2a80b5ad7f053c8bd5596f7acb33e262114.tar.gz
Improve polymorphic deserialization optimization: (#2481)
Previously, when discriminator was found as the first key in Json, but there was no deserializer for it, we still fell back to a slow path with JsonTree. It was actually meaningless because a slow path always throws exception when a serializer is not found. Such behavior led to unnecessary memory pressure & consumption in exceptional cases (see linked ticket for details). Also make polymorphic deserialization exception messages more meaningful and make them more consistent with serialization ones. Also fix behavior when the actual discriminator value is JsonNull (it should be treated as missing, not as "null" string). Fixes #2478
Diffstat (limited to 'formats/json-tests/commonTest/src/kotlinx/serialization/features/PolymorphismWithAnyTest.kt')
-rw-r--r--formats/json-tests/commonTest/src/kotlinx/serialization/features/PolymorphismWithAnyTest.kt52
1 files changed, 34 insertions, 18 deletions
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/features/PolymorphismWithAnyTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/features/PolymorphismWithAnyTest.kt
index e1d38fdd..07b6e31a 100644
--- a/formats/json-tests/commonTest/src/kotlinx/serialization/features/PolymorphismWithAnyTest.kt
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/features/PolymorphismWithAnyTest.kt
@@ -5,13 +5,13 @@
package kotlinx.serialization.features
import kotlinx.serialization.*
-import kotlinx.serialization.json.Json
+import kotlinx.serialization.json.*
import kotlinx.serialization.modules.*
import kotlinx.serialization.modules.plus
import kotlinx.serialization.test.assertStringFormAndRestored
import kotlin.test.*
-class PolymorphismWithAnyTest {
+class PolymorphismWithAnyTest: JsonTestBase() {
@Serializable
data class MyPolyData(val data: Map<String, @Polymorphic Any>)
@@ -28,19 +28,20 @@ class PolymorphismWithAnyTest {
val className = className.substringAfterLast('.')
val scopeName = scopeName.substringAfterLast('.')
val expectedText =
- "Class '$className' is not registered for polymorphic serialization in the scope of '$scopeName'"
+ "Serializer for subclass '$className' is not found in the polymorphic scope of '$scopeName'"
assertTrue(exception.message!!.startsWith(expectedText),
"Found $exception, but expected to start with: $expectedText")
}
@Test
- fun testFailWithoutModulesWithCustomClass() {
+ fun testFailWithoutModulesWithCustomClass() = parametrizedTest { mode ->
checkNotRegisteredMessage(
"kotlinx.serialization.IntData", "kotlin.Any",
assertFailsWith<SerializationException>("not registered") {
Json.encodeToString(
MyPolyData.serializer(),
- MyPolyData(mapOf("a" to IntData(42)))
+ MyPolyData(mapOf("a" to IntData(42))),
+ mode
)
}
)
@@ -51,11 +52,11 @@ class PolymorphismWithAnyTest {
val json = Json {
serializersModule = SerializersModule { polymorphic(Any::class) { subclass(IntData.serializer()) } }
}
- assertStringFormAndRestored(
+ assertJsonFormAndRestored(
expected = """{"data":{"a":{"type":"kotlinx.serialization.IntData","intV":42}}}""",
- original = MyPolyData(mapOf("a" to IntData(42))),
+ data = MyPolyData(mapOf("a" to IntData(42))),
serializer = MyPolyData.serializer(),
- format = json
+ json = json
)
}
@@ -63,14 +64,15 @@ class PolymorphismWithAnyTest {
* This test should fail because PolyDerived registered in the scope of PolyBase, not kotlin.Any
*/
@Test
- fun testFailWithModulesNotInAnyScope() {
+ fun testFailWithModulesNotInAnyScope() = parametrizedTest { mode ->
val json = Json { serializersModule = BaseAndDerivedModule }
checkNotRegisteredMessage(
"kotlinx.serialization.PolyDerived", "kotlin.Any",
assertFailsWith<SerializationException> {
json.encodeToString(
MyPolyData.serializer(),
- MyPolyData(mapOf("a" to PolyDerived("foo")))
+ MyPolyData(mapOf("a" to PolyDerived("foo"))),
+ mode
)
}
)
@@ -86,11 +88,11 @@ class PolymorphismWithAnyTest {
@Test
fun testRebindModules() {
val json = Json { serializersModule = baseAndDerivedModuleAtAny }
- assertStringFormAndRestored(
+ assertJsonFormAndRestored(
expected = """{"data":{"a":{"type":"kotlinx.serialization.PolyDerived","id":1,"s":"foo"}}}""",
- original = MyPolyData(mapOf("a" to PolyDerived("foo"))),
+ data = MyPolyData(mapOf("a" to PolyDerived("foo"))),
serializer = MyPolyData.serializer(),
- format = json
+ json = json
)
}
@@ -98,7 +100,7 @@ class PolymorphismWithAnyTest {
* This test should fail because PolyDerived registered in the scope of kotlin.Any, not PolyBase
*/
@Test
- fun testFailWithModulesNotInParticularScope() {
+ fun testFailWithModulesNotInParticularScope() = parametrizedTest { mode ->
val json = Json { serializersModule = baseAndDerivedModuleAtAny }
checkNotRegisteredMessage(
"kotlinx.serialization.PolyDerived", "kotlinx.serialization.PolyBase",
@@ -108,7 +110,8 @@ class PolymorphismWithAnyTest {
MyPolyDataWithPolyBase(
mapOf("a" to PolyDerived("foo")),
PolyDerived("foo")
- )
+ ),
+ mode
)
}
)
@@ -117,17 +120,30 @@ class PolymorphismWithAnyTest {
@Test
fun testBindModules() {
val json = Json { serializersModule = (baseAndDerivedModuleAtAny + BaseAndDerivedModule) }
- assertStringFormAndRestored(
+ assertJsonFormAndRestored(
expected = """{"data":{"a":{"type":"kotlinx.serialization.PolyDerived","id":1,"s":"foo"}},
|"polyBase":{"type":"kotlinx.serialization.PolyDerived","id":1,"s":"foo"}}""".trimMargin().lines().joinToString(
""
),
- original = MyPolyDataWithPolyBase(
+ data = MyPolyDataWithPolyBase(
mapOf("a" to PolyDerived("foo")),
PolyDerived("foo")
),
serializer = MyPolyDataWithPolyBase.serializer(),
- format = json
+ json = json
)
}
+
+ @Test
+ fun testTypeKeyLastInInput() = parametrizedTest { mode ->
+ val json = Json { serializersModule = (baseAndDerivedModuleAtAny + BaseAndDerivedModule) }
+ val input = """{"data":{"a":{"id":1,"s":"foo","type":"kotlinx.serialization.PolyDerived"}},
+ |"polyBase":{"id":1,"s":"foo","type":"kotlinx.serialization.PolyDerived"}}""".trimMargin().lines().joinToString(
+ "")
+ val data = MyPolyDataWithPolyBase(
+ mapOf("a" to PolyDerived("foo")),
+ PolyDerived("foo")
+ )
+ assertEquals(data, json.decodeFromString(MyPolyDataWithPolyBase.serializer(), input, mode))
+ }
}