Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incorrecr generic sealed-class polymorhic serializer plugin #2729

Open
sergeych opened this issue Jun 26, 2024 · 4 comments
Open

Incorrecr generic sealed-class polymorhic serializer plugin #2729

sergeych opened this issue Jun 26, 2024 · 4 comments
Labels

Comments

@sergeych
Copy link

The following code fails on compilation:

    @Serializable
    sealed class CTest<A> {
        abstract val c: Collection<A>

        @Serializable
        class AsList<A>(override val c: List<A>) : CTest<A>()
    }

    @Test
    fun testSerialization() {
        val x: CTest<Int> = CTest.AsList(
            listOf(1,2,3)
        )
        println(Json.encodeToString(x))

with strange error text:

Serializer for subclass 'Int' is not found in the polymorphic scope of 'Any'.
Check if class with serial name 'Int' exists and serializer is registered in a corresponding SerializersModule.
To be registered automatically, class 'Int' has to be '@Serializable', and the base class 'Any' has to be sealed and '@Serializable'.
kotlinx.serialization.SerializationException: Serializer for subclass 'Int' is not found in the polymorphic scope of 'Any'.
Check if class with serial name 'Int' exists and serializer is registered in a corresponding SerializersModule.
To be registered automatically, class 'Int' has to be '@Serializable', and the base class 'Any' has to be sealed and '@Serializable'.

To Reproduce

code snippet above.

Expected behavior

either correct serialization or correct error message. To be clear: Int serializer exists, and should not be requested
to be re-declared in anyway, especially in the Any, and Any should not be requested to be made sealed ;)

If such serialization can't be done automatically, please describe how it can be done by hand; i tried CTest.serializer(Int...) but
it did not help with the same error.

Environment

  • Kotlin version: 2.0.0
  • Library version: 1.7.1
  • Kotlin platforms:JVM tested but this seems to be plugin problem this platform independent
  • Gradle version: 8.1
@sandwwraith
Copy link
Member

In general, we do not support serialization to/from Any, even for basic types. In contrast with most frameworks, Json.encodeToString(listOf<Any>(1, "a", listOf("b")) produces the exception instead of [1, "a", ["b"]]. Exception you see here is aimed to describe exactly this: Int is not expected to be serialized as a part of Collection<Any>. You can try to get rid of generics and use List<Int> directly, or use JsonElements to work with untyped Json tree.
See also: #296

@sergeych
Copy link
Author

sergeych commented Jul 5, 2024

I do not mean use Any. I use generic parameter, very well known at the time of usage. It actually works if I won't use sealed class polymorphism, in the code above, serializing still-generic type CTest.AsList<A> works as expected:

  val y = CTest.AsList(listOf(1,2,3))
  println(Json.encodeToString(y)) //> {"c":[1,2,3]}

Why it works with CTest.AsList' but does not work if we use its sealed parent, CTest? And why it says "Any" while it is actually Int type?List` serializes pretty well, also in the example just above.

@pdvrieze
Copy link
Contributor

pdvrieze commented Jul 5, 2024

@sergeych I think I know what is going on. The type of x is CTest<A> where A is a generic type that is bounded by Any (this is where the any comes from. The serializer for CTest is a sealed class serializer, that will delegate serialization to its child. However, when you look at SealedClassSerializer in the library it is clear that this does not support type parameters. Instead resolution falls back to regular polymorphic resolution using the module. That resolution then considers the bound for A in AsList (Any) and tries to find a registered serializer for the subtype Int (this is not registered, thus the error).

What would need to happen is for the plugin to generate the SealedClassSerializer to contain the specialised children appropriately (and maybe do some generic magic with the baseclass' type parameter).

@sergeych
Copy link
Author

sergeych commented Jul 6, 2024

@pdvrieze I think you are right, it explains everything.

Dear maintainers, please fix the plugin to properly serialize generic sealed-class polymorphism? Right now it is not working with generic types which is not good. We need it to make real use of the kotinx serialization. Which is by far the only maintained KMP serialization I know.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants