Custom Polymorphic Serialization
See original GitHub issueDidn’t want to pollute the #29 feature request, so I’m opening a new question (or bug) issue. 😃
I tried to make a custom serializer as you suggested, following the official example https://github.com/Kotlin/kotlinx.serialization/blob/v0.20.0/runtime/commonTest/src/kotlinx/serialization/json/JsonTreeAndMapperTest.kt#L35 that is linked to from the docs about custom serializers.
In the GitHub action yml file you can have
outputs:
foo:
description: bar
value: baz
runs:
using: composite
or
outputs:
foo:
description: bar
runs:
using: something else
Meaning the output has a mandatory value
property if it is a composite
action but no value
property if it is a normal action.
Previously I didn’t support composite, so I had
@Serializable
data class GitHubAction(
/* ... */
val outputs: Map<String, Output>? = null,
/* ... */
) {
/* ... */
@Serializable
data class Output(
val description: String
)
/* ... */
}
I now changed it to
@Serializable
data class GitHubAction(
/* ... */
val outputs: Map<String, Output>? = null,
/* ... */
) {
/* ... */
sealed class Output {
abstract val description: String
data class NormalOutput(
override val description: String
) : Output()
data class CompositeOutput(
override val description: String,
val value: String
) : Output()
@Serializer(forClass = Output::class)
companion object : KSerializer<Output> {
override val descriptor: SerialDescriptor = SerialDescriptor("net.kautler.dao.GitHubAction.Output", SEALED) {
element("normal", SerialDescriptor("net.kautler.dao.GitHubAction.Output.NormalOutput") {
element("description", PrimitiveDescriptor("net.kautler.dao.GitHubAction.Output.NormalOutput.description", STRING))
})
element("composite", SerialDescriptor("net.kautler.dao.GitHubAction.Output.CompositeOutput") {
element("description", PrimitiveDescriptor("net.kautler.dao.GitHubAction.Output.CompositeOutput.description", STRING))
element("value", PrimitiveDescriptor("net.kautler.dao.GitHubAction.Output.CompositeOutput.value", STRING))
})
}
override fun deserialize(decoder: Decoder): Output {
TODO("deserialize: Not yet implemented")
}
override fun serialize(encoder: Encoder, value: Output) {
TODO("serialize: Not yet implemented")
}
}
}
/* ... */
}
The problem is, that it seems to not being used.
When I had a TODO()
in the descriptor
it failed accordingly.
But when I now try to deserialize an action file, I get complaint from kaml about missing type tag instead of the custom serializer being used.
Do I do something wrong or is there a bug in kaml?
Issue Analytics
- State:
- Created 3 years ago
- Comments:17 (9 by maintainers)
Top GitHub Comments
The issue is that you need to call
beginStructure
twice: once to start decoding the contextual structure, and then again to decode the value itself. kaml is quite strict about this, while it seems that the built-in JSON format is far more lenient.For example, the following appears to work in the sample project you provided:
@QuinnBast, if the
type
field determines what Kotlin type to use, you don’t need to use a custom serializer, you can use built-in features of kotlinx.serialization and kaml.https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/polymorphism.md describes the polymorphism support available in kotlinx.serialization, and uses the built-in JSON format for its examples.
For kaml, you can configure the YAML parser to use a property for polymorphism by setting
polymorphismStyle
toPolymorphismStyle.Property
, and settingpolymorphismPropertyName
to the name of the field you’d like to use to store type information. In your case, this istype
, which is the default value ofpolymorphismPropertyName
.