Skip to content

Delegate to default Serializer #1253

@timrijckaert

Description

@timrijckaert

Hi,

I'm dealing with an annoying JSON service which is out of my control.
If a value is unavailable it is expressed as an empty array [] instead of a canonical absence or null value.

I thought about making a custom JSON deserialiser and manually check if the value was present or not before delegating it to the default generated deserialiser.
However when defining a custom deserialiser it seems the generated deserialiser is not generated no more.

I made a simple test case here:

public object SomeObjSerializer : KSerializer<SomeObj> {
    override val descriptor: SerialDescriptor = buildClassSerialDescriptor("SomeObj")

    override fun serialize(encoder: Encoder, value: SomeObj) {}

    override fun deserialize(decoder: Decoder): SomeObj {
        val input = decoder as JsonDecoder
        val jsonObj = input.decodeJsonElement().jsonObject
        return if (jsonObj["value"] is JsonPrimitive) {
            //How to delegate to the default generated serializer?
        } else {
            SomeObj(null)
        }
    }
}

@Serializable(with = SomeObjSerializer::class)
public data class SomeObj(val value: String?)

public fun main() {
    //language=JSON
    val someJson = """{"value" : [] }"""
    val clazz = Json.decodeFromString<SomeObj>(someJson)
    
    //language=JSON
    val someOtherJson = """{"value" : "42" }"""
    val clazz2 = Json.decodeFromString<SomeObj>(someOtherJson)
}

Note that this example is a simple use case.

As a temporary solution I made a copy of my object without specifying the custom deserialiser which I reference in my own deserialiser and then map back to my original object.
However that of course does not seem to be a good solution.

public object SomeObjSerializer : KSerializer<SomeObj> {
    override val descriptor: SerialDescriptor = buildClassSerialDescriptor("SomeObj")

    override fun serialize(encoder: Encoder, value: SomeObj) {}

    override fun deserialize(decoder: Decoder): SomeObj {
        val input = decoder as JsonDecoder
        val jsonObj = input.decodeJsonElement().jsonObject
        return if (jsonObj["value"] is JsonPrimitive) {
            val obj = decoder.decodeSerializableValue(CopyOfSomeObjForDelegationPurposedOnly.serializer())
            SomeObj(obj.value)
        } else {
            SomeObj(null)
        }
    }
}

@Serializable(with = SomeObjSerializer::class)
public data class SomeObj(val value: String?)
@Serializable
public data class CopyOfSomeObjForDelegationPurposedOnly(val value: String)

public fun main() {
    //language=JSON
    val someJson = """{"value" : [] }"""
    val clazz = Json.decodeFromString<SomeObj>(someJson)

    //language=JSON
    val someOtherJson = """{"value" : "42" }"""
    val clazz2 = Json.decodeFromString<SomeObj>(someOtherJson)
}

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions