I have a situation where I want to be able to dese...
# serialization
d
I have a situation where I want to be able to deserialize JSON if the value is either a string or if it's an object with a key, returning the string value of whichever is the case, e.g.
Copy code
data class MyType(val value: String)
I want to be able to add
@Serializable(with = MyTypeSerializer::class)
and have it deserialize as described, for either:
Copy code
"my type value"
or
Copy code
{
    ...
    "expected_key": "my type value"
    ...
}
disregarding any other values in this object as they're unimportant Are there any existing serializers that help with this (similar to
JsonTransformingSerializer
, except that I need to be able to set the
@Serializable
on
MyType
so I can't use that as the generic type on
JsonTransformingSerializer
)?
a
hi, what do you mean by the generic type? If a generic type was needed I’d expect to see something like this:
Copy code
data class MyType<T>(val value: T)
d
Referring to the JsonTransformingSerializer's type
e
something like this?
Copy code
object MyTypeSerializer : KSerializer<MyType> {
    override val descriptor: SerialDescriptor = SerialDescriptor("MyType", JsonElement.serializer().descriptor)
    override fun serialize(encoder: Encoder, value: MyType) {
        encoder.encodeString(value.value)
    }
    override fun deserialize(decoder: Decoder): MyType {
        val element = (decoder as JsonDecoder).decodeJsonElement()
        val value = when (element) {
            is JsonPrimitive -> element.contentOrNull
            is JsonObject -> element["expected_key"]?.jsonPrimitive?.contentOrNull
            else -> null
        } ?: throw SerializationException("unable to deserialize")
        return MyType(value)
    }
}
d
Yeah something like this but I was hoping there might already be something so I didn't have to do the typecasting of the decoder myself
It's fine if that's what I need to do, just hoping there was something prebuilt
a
ah, JsonTransformingSerializer doesn’t have a generic type, but I see what you mean
e
you'll have to do that regardless, this sort of thing only works with Json (and maybe cbor or other json-like formats?). you definitely can't do this in other formats like protobuf
well I guess JsonTransformingSerializer performs the cast for you, but it's pretty clear from the name
d
Yep it does the encoding. The main benefit is that someone else is maintaining that expectation vs. me 😉
a
you could avoid the type-cast with a type check
Copy code
val delegate = MyTypeDelegate.serializer()
    
    override fun deserialize(decoder: Decoder): MyType {
        if (decoder !is JsonDecoder) return delegate.decode(decorder).toMyType()

        val element = decoder.decodeJsonElement()
        // ...
     }
but it doesn’t make a lot of difference if you’re only doing JSON
or even just throw a sensible error,
Copy code
if (decoder !is JsonDecoder) error("Only JSON is supported")
e
I left it out since I don't feel it adds much more detail than the CCE that
as
throws but yeah you can do that
a
yeah it’s not a big difference