Thread
#serialization
    v

    Vampire

    2 years ago
    If a field can either be a
    String
    or a
    List<String>
    in the serialized format, can this somehow be catered for with
    kotlinx.serialization
    ? In my concrete case I try using
    kaml
    to parse a GitHub workflow yml file. It can for example have this:
    jobs:
      job1:
      job2:
        needs: job1
      job3:
        needs: [job1, job2]
    Nikky

    Nikky

    2 years ago
    i think the best way would be to have a custom serializer that turns a single item list into a String and the reverse
    v

    Vampire

    2 years ago
    Do you maybe have an eye? To get the grip of a custom serializer I wanted to start with a simple overall case. I also parse a GitHub action yml file. There 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")
                }
            }
        }
        /* ... */
    }
    Two questions: • does it look correct generally or did I completely got something wrong? • why doesn't it work? The
    descriptor
    is used, when I had a
    TODO()
    in there it failed, but then on deserialization there comes an error from kaml complaining about the missing polymorphism type tag in the input so it seems the custom serializer is not used.
    Nikky

    Nikky

    2 years ago
    maye try the
    @Serializable(with=Output.Companion::class)
    annotation on the outputs property instead to force it
    v

    Vampire

    2 years ago
    The author of kaml said I should use
    CONTEXTUAL
    instead of
    SEALED
    . And it seems to indeed help. Is really
    CONTEXTUAL
    appropriate here, or is it a bug, that kaml does not respect the custom serializer? When should you use
    CONTEXTUAL
    and when
    SEALED
    generally? What is the effective difference?
    Even forcing the serializer like you suggested did not work, so I guess it indeed is a bug in kaml. But still my question, what are the differences and implications between
    CONTEXTUAL
    and
    SEALED
    as
    SEALED
    is, what the official example uses.
    Vsevolod Tolstopyatov [JB]

    Vsevolod Tolstopyatov [JB]

    2 years ago
    For JSON we have JsonTransformingSerializer: https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/json.md#json-transformations For kaml a special support from kaml format implementation is required
    v

    Vampire

    2 years ago
    Yep, already requested that, but maintainer does not have that many time for implementing it. But in the meantime I already solved everything using custom serializers. 😃