You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Describe the bug
I have a Singleton object, for which I am trying to implement a KSerializer.
Serializer works fine only if it is used outside of polymorphic context.
When it is used in polymorphic context deserialization fails with unexpected exception:
* Unexpected JSON token at offset 9: Expected end of the object '}', but had '"' instead at path: $.type
* JSON input: {"type":{"type":"Singleton"}}
* kotlinx.serialization.json.internal.JsonDecodingException: Unexpected JSON token at offset 9: Expected end of the object '}', but had '"' instead at path: $.type
* JSON input: {"type":{"type":"Singleton"}}
1)Am I doing something wrong, or it is the library issue?
2) looks that I have to use api marked as internal (not working also) - buildSerialDescriptor("Singleton", StructureKind.OBJECT)
To Reproduce
Attach a code snippet or test data if possible.
I have provided 4 tests.
1 and 2 looks approximately like I expect, but they fail, 3 and 4 are workarounds that I have tried.
packagecom.nsk.testimportio.kotest.core.spec.style.StringSpecimportkotlinx.serialization.InternalSerializationApiimportkotlinx.serialization.KSerializerimportkotlinx.serialization.Serializableimportkotlinx.serialization.builtins.nullableimportkotlinx.serialization.builtins.serializerimportkotlinx.serialization.descriptors.*importkotlinx.serialization.encodeToStringimportkotlinx.serialization.encoding.*importkotlinx.serialization.json.Jsonimportkotlinx.serialization.modules.SerializersModuleimportkotlinx.serialization.modules.polymorphic/** Requires custom serializer */privateinterfacePolymorphicType/** Requires custom serializer */privateobject Singleton : PolymorphicType
@Serializable
privatedata classMyData(valtype:PolymorphicType)
/** * Does not work. * Uses [buildClassSerialDescriptor]*/privateobject NotWorkingSingletonSerializer : KSerializer<Singleton> {
overrideval descriptor = buildClassSerialDescriptor("Singleton")
overridefunserialize(encoder:Encoder, value:Singleton) {
encoder.encodeStructure(descriptor) {}
}
overridefundeserialize(decoder:Decoder): Singleton {
return decoder.decodeStructure(descriptor) { Singleton }
}
}
/** * Does not work. * This looks like correct variant for me, but is uses internal api with [StructureKind.OBJECT]*/privateobject NotWorkingObjectSingletonSerializer : KSerializer<Singleton> {
@OptIn(InternalSerializationApi::class)
// have to use internal apioverrideval descriptor = buildSerialDescriptor("Singleton", StructureKind.OBJECT)
overridefunserialize(encoder:Encoder, value:Singleton) {
encoder.encodeStructure(descriptor) {}
}
overridefundeserialize(decoder:Decoder): Singleton {
return decoder.decodeStructure(descriptor) { Singleton }
}
}
/** * Works fine * But I have to add fake field*/privateobject WorkingSerializableSerializer : KSerializer<Singleton> {
overrideval descriptor = buildClassSerialDescriptor("Singleton") {
element<Boolean>("field_to_fix_an_issue")
}
overridefunserialize(encoder:Encoder, value:Singleton) {
encoder.encodeStructure(descriptor) {
encodeBooleanElement(descriptor, 0, false)
}
}
overridefundeserialize(decoder:Decoder): Singleton {
return decoder.decodeStructure(descriptor) {
while (true) {
when (val index = decodeElementIndex(descriptor)) {
0-> decodeBooleanElement(descriptor, 0) // just read itCompositeDecoder.DECODE_DONE->breakelse-> error("Unexpected index: $index")
}
}
Singleton
}
}
}
/** * Works fine, allows to omit "field_to_fix_an_issue" in json, but it is still in code.*/privateobject WorkingOptionalSerializableSerializer : KSerializer<Singleton> {
overrideval descriptor = buildClassSerialDescriptor("Singleton") {
element("field_to_fix_an_issue", Boolean.serializer().nullable.descriptor, isOptional =true)
}
overridefunserialize(encoder:Encoder, value:Singleton) {
encoder.encodeStructure(descriptor) {
encodeNullableSerializableElement(descriptor, 0, Boolean.serializer().nullable, null)
}
}
overridefundeserialize(decoder:Decoder): Singleton {
return decoder.decodeStructure(descriptor) {
while (true) {
when (val index = decodeElementIndex(descriptor)) {
0-> decodeNullableSerializableElement(descriptor, 0, Boolean.serializer().nullable) // just read itCompositeDecoder.DECODE_DONE->breakelse-> error("Unexpected index: $index")
}
}
Singleton
}
}
}
classObjectSerializationTest : StringSpec({
"test1 NotWorkingSingletonSerializer - fail" {
val jsonFormat = Json {
serializersModule = SerializersModule {
polymorphic(PolymorphicType::class) {
subclass(Singleton::class, NotWorkingSingletonSerializer)
}
}
}
val json = jsonFormat.encodeToString(MyData(Singleton))
println(json) // {"type":{"type":"Singleton"}}val data = jsonFormat.decodeFromString<MyData>(json)
/* * deserialization exception: * Unexpected JSON token at offset 9: Expected end of the object '}', but had '"' instead at path: $.type * JSON input: {"type":{"type":"Singleton"}} * kotlinx.serialization.json.internal.JsonDecodingException: Unexpected JSON token at offset 9: Expected end of the object '}', but had '"' instead at path: $.type * JSON input: {"type":{"type":"Singleton"}}*/
}
"test2 NotWorkingObjectSingletonSerializer - fail" {
val jsonFormat = Json {
serializersModule = SerializersModule {
polymorphic(PolymorphicType::class) {
subclass(Singleton::class, NotWorkingObjectSingletonSerializer)
}
}
}
val json = jsonFormat.encodeToString(MyData(Singleton))
println(json) // {"type":{"type":"Singleton"}}val data = jsonFormat.decodeFromString<MyData>(json)
/* * deserialization exception: * Unexpected JSON token at offset 9: Expected end of the object '}', but had '"' instead at path: $.type * JSON input: {"type":{"type":"Singleton"}} * kotlinx.serialization.json.internal.JsonDecodingException: Unexpected JSON token at offset 9: Expected end of the object '}', but had '"' instead at path: $.type * JSON input: {"type":{"type":"Singleton"}}*/
}
"test3 WorkingSerializableSerializer - ok" {
val jsonFormat = Json {
serializersModule = SerializersModule {
polymorphic(PolymorphicType::class) {
subclass(Singleton::class, WorkingSerializableSerializer)
}
}
}
val json = jsonFormat.encodeToString(MyData(Singleton))
println(json) // {"type":{"type":"Singleton","field_to_fix_an_issue":false}}val data = jsonFormat.decodeFromString<MyData>(json)
}
"test4 WorkingOptionalSerializableSerializer - ok" {
val jsonFormat = Json {
serializersModule = SerializersModule {
polymorphic(PolymorphicType::class) {
subclass(Singleton::class, WorkingOptionalSerializableSerializer)
}
}
}
val json = jsonFormat.encodeToString(MyData(Singleton))
println(json) // {"type":{"type":"Singleton","field_to_fix_an_issue":false}} or {"type":{"type":"Singleton"}}val data = jsonFormat.decodeFromString<MyData>(json)
}
})
Expected behavior
All 4 cases pass successfully
Environment
Kotlin version: [2.0.20]
Library version: [1.7.3]
Kotlin platforms: [JVM]
Gradle version: [7.6.1]
IDE version -
The text was updated successfully, but these errors were encountered:
nsk90
added a commit
to KStateMachine/kstatemachine
that referenced
this issue
Oct 16, 2024
val type = lexer.peekLeadingMatchingValue(discriminator, configuration.isLenient)
) does not actually consume this string from input. Therefore, it has to be skipped by other means. For generated code, it happens in decodeElementIndex call which would skip type key known to be a discriminator. To workaround this in your code, you can make this call as well:
Describe the bug
I have a Singleton object, for which I am trying to implement a
KSerializer
.Serializer works fine only if it is used outside of polymorphic context.
When it is used in polymorphic context deserialization fails with unexpected exception:
1)Am I doing something wrong, or it is the library issue?
2) looks that I have to use api marked as internal (not working also) -
buildSerialDescriptor("Singleton", StructureKind.OBJECT)
To Reproduce
Attach a code snippet or test data if possible.
I have provided 4 tests.
1 and 2 looks approximately like I expect, but they fail, 3 and 4 are workarounds that I have tried.
Expected behavior
All 4 cases pass successfully
Environment
The text was updated successfully, but these errors were encountered: