kotlinx.serialization icon indicating copy to clipboard operation
kotlinx.serialization copied to clipboard

Error in deserialize function for parameterized abstract and sealed classes

Open shanshin opened this issue 4 years ago • 4 comments

Describe the bug Errors occurred when trying to deserialize instances for parameterized abstract and sealed classes.

To Reproduce

    @Serializable
    sealed class TypedSealedClass<T>(val a: T) {
        @Serializable
        data class Child(val y: Int) : TypedSealedClass<Int>(10)
    }

and try to deserialize it

        val child = Json.encodeToString(TypedSealedClass.serializer(Int.serializer()), TypedSealedClass.Child(10))
        Json.decodeFromString(TypedSealedClass.serializer(Int.serializer()), child)

For JVM backend error occurred

java.lang.NoSuchFieldError: typeSerial0
	at com.jetbrains.example.serialization.MainTest$TypedSealedClass$Child$$serializer.deserialize(Project.kt)
	at com.jetbrains.example.serialization.MainTest$TypedSealedClass$Child$$serializer.deserialize(Project.kt:23)
	at kotlinx.serialization.json.internal.PolymorphicKt.decodeSerializableValuePolymorphic(Polymorphic.kt:63)
	at kotlinx.serialization.json.internal.AbstractJsonTreeDecoder.decodeSerializableValue(TreeJsonDecoder.kt:51)
	at kotlinx.serialization.json.internal.TreeJsonDecoderKt.readPolymorphicJson(TreeJsonDecoder.kt:32)
	at kotlinx.serialization.json.internal.PolymorphicKt.decodeSerializableValuePolymorphic(Polymorphic.kt:73)
	at kotlinx.serialization.json.internal.StreamingJsonDecoder.decodeSerializableValue(StreamingJsonDecoder.kt:33)
	at kotlinx.serialization.json.Json.decodeFromString(Json.kt:85)
        ...

for JVM IR

e: java.lang.IndexOutOfBoundsException: Index 0 out of bounds for length 0
	at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:64)
	at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:70)
	at java.base/jdk.internal.util.Preconditions.checkIndex(Preconditions.java:248)
	at java.base/java.util.Objects.checkIndex(Objects.java:372)
	at java.base/java.util.ArrayList.get(ArrayList.java:458)
	at org.jetbrains.kotlinx.serialization.compiler.backend.ir.IrBuilderExtension$serializerInstance$1.invoke(GeneratorHelpers.kt:623)
	at org.jetbrains.kotlinx.serialization.compiler.backend.ir.IrBuilderExtension$serializerInstance$1.invoke(GeneratorHelpers.kt:622)
	at org.jetbrains.kotlinx.serialization.compiler.backend.ir.IrBuilderExtension$DefaultImpls.serializerInstance(GeneratorHelpers.kt:639)
	at org.jetbrains.kotlinx.serialization.compiler.backend.ir.SerializerIrGenerator.serializerInstance(SerializerIrGenerator.kt:45)
	at org.jetbrains.kotlinx.serialization.compiler.backend.ir.IrBuilderExtension$DefaultImpls.serializerInstance(GeneratorHelpers.kt:616)
	at org.jetbrains.kotlinx.serialization.compiler.backend.ir.SerializerIrGenerator.serializerInstance(SerializerIrGenerator.kt:45)
	at org.jetbrains.kotlinx.serialization.compiler.backend.ir.SerializerIrGenerator$generateSave$1.invoke(SerializerIrGenerator.kt:540)
	at org.jetbrains.kotlinx.serialization.compiler.backend.ir.SerializerIrGenerator$generateSave$1.invoke(SerializerIrGenerator.kt:236)
	at org.jetbrains.kotlinx.serialization.compiler.backend.ir.IrBuilderExtension$DefaultImpls.contributeFunction(GeneratorHelpers.kt:55)
	at org.jetbrains.kotlinx.serialization.compiler.backend.ir.SerializerIrGenerator.contributeFunction(SerializerIrGenerator.kt:45)
	at org.jetbrains.kotlinx.serialization.compiler.backend.ir.SerializerIrGenerator.generateSave(SerializerIrGenerator.kt:236)
	at org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializerCodegen.generateSaveIfNeeded(SerializerCodegen.kt:109)
	at org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializerCodegen.generate(SerializerCodegen.kt:37)
        ...

same for abstract classes

Expected behavior deserialize finished successfully

Environment

  • Kotlin version: 1.4.30-M1
  • Library version: 1.0.1
  • Kotlin platforms: JVM, JVM IR

shanshin avatar Dec 23 '20 19:12 shanshin

Got the same exception both on JVM-IR and JS-IR during compillation.

altavir avatar Feb 10 '21 19:02 altavir

Also https://youtrack.jetbrains.com/issue/KT-43910

sandwwraith avatar Apr 28 '21 18:04 sandwwraith

https://youtrack.jetbrains.com/issue/KT-49660

abelkov avatar Nov 17 '21 11:11 abelkov

This is still an issue in "org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.0" in combination with Kotlin 1.7.10 and Java 17.

phreakadelle2k avatar Aug 25 '22 20:08 phreakadelle2k

This is still an issue in "org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.0" in combination with Kotlin 1.7.10 and Java 17.

What if working with other versions of kotlin? Are there any workarounds at currently?

manuqiao avatar Sep 27 '22 01:09 manuqiao

There's an easy workaround, the goal is to get rid of concrete property in parent class:

Change

    @Serializable
    sealed class TypedSealedClass<T>(val a: T) {
        @Serializable
        data class Child(val y: Int) : TypedSealedClass<Int>(10)
    }

Into

    @Serializable
    sealed class TypedSealedClass<T>() {
        abstract val a: T
        
        @Serializable
        data class Child(val y: Int) : TypedSealedClass<Int>() {
            @EncodeDefault override val a: Int = 10
        }
    }

sandwwraith avatar Oct 04 '22 16:10 sandwwraith

There's an easy workaround, the goal is to get rid of concrete property in parent class:

Change

    @Serializable
    sealed class TypedSealedClass<T>(val a: T) {
        @Serializable
        data class Child(val y: Int) : TypedSealedClass<Int>(10)
    }

Into

    @Serializable
    sealed class TypedSealedClass<T>() {
        abstract val a: T
        
        @Serializable
        data class Child(val y: Int) : TypedSealedClass<Int>() {
            @EncodeDefault override val a: Int = 10
        }
    }

It works. Thanks a lot.

manuqiao avatar Oct 12 '22 06:10 manuqiao