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

Polymorphic (de)serialization crashes with inline class #2049

Closed
bubenheimer opened this issue Oct 7, 2022 · 4 comments
Closed

Polymorphic (de)serialization crashes with inline class #2049

bubenheimer opened this issue Oct 7, 2022 · 4 comments
Assignees

Comments

@bubenheimer
Copy link

bubenheimer commented Oct 7, 2022

Describe the bug

A sealed interface hierarchy containing an inline class fails on polymorphic (de)serialization. Depending on specific (de)serialization method used, different errors occur:

With decodeFromString():

kotlinx.serialization.json.internal.JsonDecodingException: Expected class kotlinx.serialization.json.JsonObject (Kotlin reflection is not available) as the serialized body of MyPoly, but had class kotlinx.serialization.json.JsonLiteral (Kotlin reflection is not available)

With encodeToJsonElement():

kotlinx.serialization.SerializationException: No tag in stack for requested element

To Reproduce

@Serializable
sealed interface MyPoly {
    @Serializable
    object Invalid : MyPoly

    @Serializable
    @JvmInline
    value class Valid(val value: String) : MyPoly
}

Environment

  • Kotlin version: 1.7.20
  • Library version: 1.4.0
  • Kotlin platforms: JVM

As for a workaround: is there anything simple besides turning the inline class into a data class?

@bubenheimer bubenheimer changed the title Polymorphic serialization crashes with inline class Polymorphic (de)serialization crashes with inline class Oct 7, 2022
@sandwwraith
Copy link
Member

The problem is actually on the side of initial serialization — it should be prohibited.
We can't serialize primitives polymorphically, because there's no place to insert "type":"MyPoly.Valid" class discriminator.
When we serialize a value class polymorphically, we simply get "value" string — and the deserializer expects an object to find a type key within it.

As a workaround, you can switch to Json { useArrayPolymorphism = true } or replace the value class with a data class.

@bubenheimer
Copy link
Author

bubenheimer commented Oct 7, 2022

Is it possible to do this with a custom serializer for the value class? I had tried a simple one (with PrimitiveKind.String), but that only lead me toward useArrayPolymorphism = true as you mentioned. Would a different, non-PrimitiveKind custom serializer work, or is this just not an option?

I am hesitant about useArrayPolymorphism because

This is an option for legacy JSON format and should not be generally used.

@bubenheimer
Copy link
Author

To answer my own question: polymorphic serialization of value class works with non-PrimitiveKind custom serializer.

Ultimately, the best approach for my particular use case may be a custom serializer at the sealed interface level.

@sandwwraith
Copy link
Member

After giving it a second thought, I can say that problem with the writing of a value class is a duplicate of #1774. Once it is fixed, it would be possible to write a value class (without a discriminator, though). It is still impossible to read it back automatically, but you can fix it with a custom content-based serializer like here: #2159

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

No branches or pull requests

2 participants