I am facing issues with serialization using Kotlin. I've followed through the steps here https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/serialization-guide.md but unfortunately, no luck...
This is my code:
sealed interface Convertible {
fun convertUserInput(value : String): String
}
@Serializable
@SerialName("CustomConvertible")
class CustomConvertible(): Convertible {
override fun convertUserInput(value : String): String {
return ""
}
}
@Serializable
class DTOAttribute(val convertibles : List<Convertible> = emptyList())
Later on, I'd like to encode the DTOAttribute
with val string = Json.encodeToString(dtoAttr)
Calling this, gives me the following exception:
kotlinx.serialization.SerializationException: Class 'CustomConvertible' is not registered for polymorphic serialization in the scope of 'Convertible'.
Mark the base class as 'sealed' or register the serializer explicitly.
This confuses me, as I've marked the interface as sealed
and used @Serializable
.
Versions build.gradle
plugins{
kotlin("jvm")
kotlin("plugin.serialization") version("1.6.10")
...
sourceSets{
named("main") {
dependencies {
...
api("org.jetbrains.kotlin:kotlin-reflect:1.6.10")
api("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.2")
}
}
}
org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.2
What else am I missing then?
CodePudding user response:
Update: you're using Kotlin 1.6.10, but KxS didn't support serializing sealed interfaces until 1.6.20
If you can update to 1.6.20 , then adding @Serializable
to Convertible
works.
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
@Serializable
sealed interface Convertible {
fun convertUserInput(value: String): String
}
@Serializable
@SerialName("CustomConvertible")
class CustomConvertible : Convertible {
override fun convertUserInput(value: String): String {
return ""
}
}
@Serializable
class DTOAttribute(
val convertibles: List<Convertible> = emptyList()
)
fun main() {
val dtoAttribute = DTOAttribute(listOf(CustomConvertible()))
val string = Json.encodeToString(dtoAttribute)
println(string)
// {"convertibles":[{"type":"CustomConvertible"}]}
}
If I remove @Serializable
I get the same error that you report
//@Serializable
sealed interface Convertible {
fun convertUserInput(value: String): String
}
Exception in thread "main" kotlinx.serialization.SerializationException: Class 'CustomConvertible' is not registered for polymorphic serialization in the scope of 'Convertible'.
Mark the base class as 'sealed' or register the serializer explicitly.
Versions
- Kotlinx Serialization 1.3.3
- Kotlin/JVM 1.7.10
Workaround for 1.6.10 - sealed class
If you can't update your version of Kotlin then you can convert Convertible
to be a sealed class.
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
@Serializable
sealed class Convertible {
abstract fun convertUserInput(value: String): String
}
@Serializable
@SerialName("CustomConvertible")
class CustomConvertible : Convertible() {
override fun convertUserInput(value: String): String {
return ""
}
}
@Serializable
class DTOAttribute(
val convertibles: List<Convertible> = emptyList()
)
fun main() {
val dtoAttribute = DTOAttribute(listOf(CustomConvertible()))
val string = Json.encodeToString(dtoAttribute)
println(string)
// {"convertibles":[{"type":"CustomConvertible"}]}
}
Setup
Here's how to setup using Gradle Kotlin DSL (from the README):
// build.gradle.kts
plugins {
kotlin("jvm") version "1.7.10" // or kotlin("multiplatform") or any other kotlin plugin
kotlin("plugin.serialization") version "1.7.10"
}
dependencies {
implementation(platform("org.jetbrains.kotlinx:kotlinx-serialization-bom:1.3.3"))
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json")
}