Hi, I have a previously defined JSON format that I...
# serialization
k
Hi, I have a previously defined JSON format that I need to be compatible with. The JSON is made up of typekey-objects pairs. Usually in a list of different kinds. Here are a couple examples:
{
"UTCTimeKey" : {
"keyName" : "StartTimes",
"values" : [ "1970-01-01T00:00:00Z", "2023-04-13T20:23:51.953536907Z" ],
"units" : "utc"
}
}, {
"IntKey" : {
"keyName" : "Power",
"values" : [ 70 ],
"units" : "volts"
}
}
The typekey tells deserializing how to handle the RHS. These two examples have right hand sides that are the same, but in general the RHS can have varied properties. What I want to do is look at the typekey and dispatch the serialization to a specialized serializer. I’ve asked about this before and a very helpful response led me to the JsonContetPolymorphicSerializer, which works fine. Here is an example:
Copy code
object ParamDeserializer : JsonContentPolymorphicSerializer<HasKey>(HasKey::class) {
    override fun selectDeserializer(content: JsonElement) = when {
        "DoubleKey" in content.jsonObject -> NumberSerializer
        "LongKey" in content.jsonObject -> IntegerSerializer
        "StringKey" in content.jsonObject -> StringSerializer
        "BooleanKey" in content.jsonObject -> BooleanSerializer
        "ChoiceKey" in content.jsonObject -> ChoiceSerializer
        else -> throw IllegalArgumentException("Unknown type key")
    }
}
This works, but we also need to serialize to CBOR and this solution is JSON-only. Does anyone have suggestions on how to write this code in a way that works for JSON and CBOR? I’ve banged on this for quite a while so thanks for any suggestions!
e
sounds like a case for a surrogate serializer
k
Thanks @ephemient. The surrogate approach is definitely my good friend, but I’ve not tried what you’ve provided. I’ll give it a go and report back. Thanks for your help!
Thanks again for the code example @ephemient. This example is elegant and something I would not think of at my current level! There remains a couple problems — both somewhat related. First, I have keys that have different names and are different in the code but are encoded in JSON similarly. For instance, there is s “ChoiceKey” for enumerated values, that encodes like StringKey with String values. The other thing is there are some complex keys with multiple values. A CoordKey for instance, has an ra and dec field (I am working in astronomy). This is why the original dispatches to other serializers. But your solution is much nicer than what I was doing. Thanks again, and if you have any ideas on how to extend it (which I will try too), much appreciated.
e
it shouldn't be hard to extend, just add e.g.
Copy code
@SerialName("CoordKey")
    val coord: CoordValue? = null,
) {
    @Serializable
    data class CoordValue(val keyName: String, val ra: Double, val dec: Double)
I just made them a common
Value<T>
type above for convenience. of course, you'll have to decide how you represent them in your public
Param
interface, but that's up to you