Skip to content

Commit 5c2029a

Browse files
committed
Unify Polymorphic and Sealed class serializers check:
now it is allowed to have a conflicting name on deserialization, conflicts are reported only during encoding.
1 parent d084417 commit 5c2029a

File tree

3 files changed

+40
-30
lines changed

3 files changed

+40
-30
lines changed

formats/json-tests/commonTest/src/kotlinx/serialization/features/JsonClassDiscriminatorTest.kt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import kotlinx.serialization.*
88
import kotlinx.serialization.builtins.*
99
import kotlinx.serialization.json.*
1010
import kotlinx.serialization.modules.*
11+
import kotlinx.serialization.test.assertFailsWithMessage
1112
import kotlin.test.*
1213

1314
class JsonClassDiscriminatorTest : JsonTestBase() {
@@ -110,4 +111,21 @@ class JsonClassDiscriminatorTest : JsonTestBase() {
110111
json
111112
)
112113
}
114+
115+
@Serializable
116+
@JsonClassDiscriminator("type2")
117+
@SerialName("Foo")
118+
sealed interface Foo
119+
120+
@Serializable
121+
@SerialName("FooImpl")
122+
data class FooImpl(val type2: String) : Foo
123+
124+
@Test
125+
fun testCannotHaveConflictWithJsonClassDiscriminator() {
126+
assertFailsWithMessage<SerializationException>("Class 'FooImpl' cannot be serialized as base class 'Foo' because it has property name that conflicts with JSON class discriminator 'type2'") {
127+
Json.encodeToString<Foo>( FooImpl("foo"))
128+
}
129+
}
130+
113131
}

formats/json-tests/commonTest/src/kotlinx/serialization/modules/SerialNameCollisionTest.kt

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package kotlinx.serialization.modules
66

77
import kotlinx.serialization.*
88
import kotlinx.serialization.json.*
9+
import kotlinx.serialization.test.assertFailsWithMessage
910
import kotlin.test.*
1011

1112
private const val prefix = "kotlinx.serialization.modules.SerialNameCollisionTest"
@@ -34,7 +35,6 @@ class SerialNameCollisionTest {
3435
classDiscriminator = discriminator
3536
this.useArrayPolymorphism = useArrayPolymorphism
3637
serializersModule = context
37-
3838
}
3939

4040
@Test
@@ -45,9 +45,15 @@ class SerialNameCollisionTest {
4545
}
4646
}
4747

48-
assertFailsWith<IllegalArgumentException> { Json("type", module) }
49-
assertFailsWith<IllegalArgumentException> { Json("type2", module) }
50-
Json("type3", module) // OK
48+
assertFailsWithMessage<SerializationException>("Class 'kotlinx.serialization.modules.SerialNameCollisionTest.Derived' cannot be serialized as base class 'kotlinx.serialization.Polymorphic<Base>' because it has property name that conflicts with JSON class discriminator 'type'.") {
49+
Json("type", module).encodeToString<Base>(Derived("foo", "bar"))
50+
}
51+
assertFailsWithMessage<SerializationException>("Class 'kotlinx.serialization.modules.SerialNameCollisionTest.Derived' cannot be serialized as base class 'kotlinx.serialization.Polymorphic<Base>' because it has property name that conflicts with JSON class discriminator 'type2'.") {
52+
Json("type2", module).encodeToString<Base>(Derived("foo", "bar"))
53+
}
54+
assertEquals("{\"type3\":\"kotlinx.serialization.modules.SerialNameCollisionTest.Derived\",\"type\":\"foo\",\"type2\":\"bar\"}",
55+
Json("type3", module).encodeToString<Base>(Derived("foo", "bar"))
56+
)
5157
}
5258

5359
@Test
@@ -68,10 +74,18 @@ class SerialNameCollisionTest {
6874
}
6975
}
7076

71-
assertFailsWith<IllegalArgumentException> { Json("type", module) }
72-
assertFailsWith<IllegalArgumentException> { Json("type2", module) }
73-
assertFailsWith<IllegalArgumentException> { Json("t3", module) }
74-
Json("t4", module) // OK
77+
assertFailsWithMessage<SerializationException>("Class 'kotlinx.serialization.modules.SerialNameCollisionTest.DerivedCustomized' cannot be serialized as base class 'kotlinx.serialization.Polymorphic<Base>' because it has property name that conflicts with JSON class discriminator 'type'.") {
78+
Json("type", module).encodeToString<Base>(DerivedCustomized("foo", "bar", "t3"))
79+
}
80+
assertFailsWithMessage<SerializationException>("Class 'kotlinx.serialization.modules.SerialNameCollisionTest.DerivedCustomized' cannot be serialized as base class 'kotlinx.serialization.Polymorphic<Base>' because it has property name that conflicts with JSON class discriminator 'type2'.") {
81+
Json("type2", module).encodeToString<Base>(DerivedCustomized("foo", "bar", "t3"))
82+
}
83+
assertFailsWithMessage<SerializationException>("Class 'kotlinx.serialization.modules.SerialNameCollisionTest.DerivedCustomized' cannot be serialized as base class 'kotlinx.serialization.Polymorphic<Base>' because it has property name that conflicts with JSON class discriminator 't3'.") {
84+
Json("t3", module).encodeToString<Base>(DerivedCustomized("foo", "bar", "t3"))
85+
}
86+
assertEquals("{\"t4\":\"kotlinx.serialization.modules.SerialNameCollisionTest.DerivedCustomized\",\"type\":\"foo\",\"type2\":\"bar\",\"t3\":\"t3\"}",
87+
Json("t4", module).encodeToString<Base>(DerivedCustomized("foo", "bar", "t3"))
88+
)
7589

7690
}
7791

formats/json/commonMain/src/kotlinx/serialization/json/internal/JsonSerializersModuleValidator.kt

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ internal class JsonSerializersModuleValidator(
1515
configuration: JsonConfiguration,
1616
) : SerializersModuleCollector {
1717

18-
private val discriminator: String = configuration.classDiscriminator
1918
private val useArrayPolymorphism: Boolean = configuration.useArrayPolymorphism
2019
private val isDiscriminatorRequired = configuration.classDiscriminatorMode != ClassDiscriminatorMode.NONE
2120

@@ -33,10 +32,6 @@ internal class JsonSerializersModuleValidator(
3332
) {
3433
val descriptor = actualSerializer.descriptor
3534
checkKind(descriptor, actualClass)
36-
if (!useArrayPolymorphism && isDiscriminatorRequired) {
37-
// Collisions with "type" can happen only for JSON polymorphism
38-
checkDiscriminatorCollisions(descriptor, actualClass)
39-
}
4035
}
4136

4237
private fun checkKind(descriptor: SerialDescriptor, actualClass: KClass<*>) {
@@ -62,23 +57,6 @@ internal class JsonSerializersModuleValidator(
6257
}
6358
}
6459

65-
private fun checkDiscriminatorCollisions(
66-
descriptor: SerialDescriptor,
67-
actualClass: KClass<*>
68-
) {
69-
for (i in 0 until descriptor.elementsCount) {
70-
val name = descriptor.getElementName(i)
71-
if (name == discriminator) {
72-
throw IllegalArgumentException(
73-
"Polymorphic serializer for $actualClass has property '$name' that conflicts " +
74-
"with JSON class discriminator. You can either change class discriminator in JsonConfiguration, " +
75-
"rename property with @SerialName annotation " +
76-
"or fall back to array polymorphism"
77-
)
78-
}
79-
}
80-
}
81-
8260
override fun <Base : Any> polymorphicDefaultSerializer(
8361
baseClass: KClass<Base>,
8462
defaultSerializerProvider: (value: Base) -> SerializationStrategy<Base>?

0 commit comments

Comments
 (0)