Open
Description
Describe the bug
Having Json configured with coerceInputValues = true
results in Enums not being deserialized if they have a custom serializer. If a value is predefined in the data object, it uses the predefined value, if it has to be passed as a constructor parameter, deserialization fails because it is "missing"
Set a breakpoint in the first line of BarSerialiizer.deserialize, but debugger did not go there, no further error message etc.
To Reproduce
import kotlinx.serialization.*
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.descriptors.SerialKind.ENUM
import kotlinx.serialization.descriptors.buildSerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.json.Json
import kotlin.test.Test
import kotlin.test.assertEquals
@Serializable
enum class Foo {
A,
B
}
@Serializable(with = BarSerializer::class)
enum class Bar {
C,
D
}
object BarSerializer : KSerializer<Bar> {
override val descriptor: SerialDescriptor = buildSerialDescriptor("BarSerializer", ENUM)
override fun deserialize(decoder: Decoder): Bar {
val stringValue = decoder.decodeString()
return try {
Bar.valueOf(stringValue)
}
catch (e: IllegalArgumentException) {
Bar.C
}
}
override fun serialize(encoder: Encoder, value: Bar) {
encoder.encodeString(value.name)
}
}
@Serializable
class SomeClass {
var foo: Foo = Foo.A
var bar: Bar = Bar.C
}
@Serializable
class OtherClass(var foo:Foo,var bar:Bar)
class EnumBugTest {
@Test
fun serializerNotUsed() {
// given
val json = """
{
"foo":"B",
"bar":"D"
}
""".trimIndent()
// when
val obj: SomeClass = Json {
coerceInputValues = true
}.decodeFromString(json)
// then
assertEquals(Foo.B, obj.foo)
assertEquals(Bar.D, obj.bar) // fails because it uses the default value Bar.C in SomeClass
}
@Test
fun otherClassTest(){
// given
val json = """
{
"foo":"B",
"bar":"D"
}
""".trimIndent()
// when
val obj: OtherClass = Json {
coerceInputValues = true
}.decodeFromString(json) // fails because field "bar" is "missing"
// then
assertEquals(Foo.B, obj.foo)
assertEquals(Bar.D, obj.bar)
}
}
Expected behavior
The defined serializer should be used
Environment
- Kotlin version:1.6.21
- Library version: 1.3.2
- Kotlin platforms: JVM
- Gradle version: 7.1.1