I'm sure this has been asked 20 times, but how can...
# serialization
b
I'm sure this has been asked 20 times, but how can I serialize something like :
Copy code
data class Vega(
    val background: StringOrMoreComplex
)
e
depends on what is StringOrMoreComplex
b
either a String or something @Serializable
I know at compile time what it can be
e
if it were
Copy code
@Serializable
data class Vega<T>(
    val background: T
)
you'd have no issues (at least not here). that level of knowing at compile-time?
b
The Json is either {background: "#FFFFFF"} or {background: {somemoreJson}}
ok I though about doing that way, let me try that
I tried to understand how polymorphism work
but all I could get was {background: {something}} not the direct string
e
this isn't polymorphism. you'd need to know ahead of time, at compile time, if you're serializing/deserializing a Vega<String> or a Vega<JsonObject>
if you do want polymorphism at runtime, that would require writing a custom serializer
b
is there an example of something like that? I may want to do that at some point
e
I don't think kotlinx.serialization would be very happy with it changing shape between String and Object, though - you can probably make it work on JSON by doing some preprocessing, but it won't work on other formats
b
this is only for JSON.
The problem is that I have many types that are StringOrSomethingSerializable
This is what I try to make a DSL for: https://vega.github.io/vega/docs/specification/
I want to be able to generate JSON with that format
maybe I need to use a more dynamic JSON library for that. But I liked the idea to have a clean data classes to describe the format
ok I managed to write a custom serializer that works well enough
I'll do the deserializer just in case as well
I'm not super fan of the deserializer, as I'm doing a try catch when trying to do a decodeString that then tries to decode the object
but it seems to work really well so far
I'm also not sure what the descriptor should be in those cases
e
b
hum let me share what I did
(I had a way with sealed classes instead of the interface before, was just trying the inline classes here)
e
try { decoder.decodeString()
can cause issues as the decoder isn't rewindable
b
the json one is not?
ok it seemed to have worked in my tests in which case can it fail?
e
well, with Json it happens to work ok because of how it's tokenized, but IMO doing some pre-processing on JsonElement to get it into the form that kotlinx.serialization.json likes is safer IMO
b
ok I'll check your way as well
especially with triple unions
would your way work out of the JVM as well?
e
yeah, your approach will have some issues with that with multiple object types
yes, this is all common
b
great
thanks !
e
if that ends up not working for you, then look into JsonContentPolymorphicSerializer
b
Now I'm confused
it works even without the serializer
oh I see why… 🤦‍♂️
With your approach I get an error about the tSerializer parameter being null in JsonTransformingSerializer.<init>
oh I missed the @file
is there a way to make that global to a json object?
e
unfortunately not
b
I can't get your solution to work, it still tells me that the Background.serializer() is null
oh nevermind I forgot a with…
e
well ok, if you poke into
@InternalSerializationApi
then this is doable. also if you use Kotlin 1.5's
sealed interface
(usable on Kotlin 1.4.3x if you add
kotlinOptions.languageVersion = "1.5"
) then you can have
Signal
in multiple sealed hierarchies
b
I can't seem to be able to use your serializer
even with the @file… annotation
e
really? that file runs here with no issues...
b
How do you get Signal shared between multiple classes?
oooh yes with the sealed interface
your last way works, I'm not a fan of using the internalApi
but it works beautifuly
With your way I don't know how to make the deserializer for objects that can be three different things
I come back to the same issue I had initially (and why I used try/catch)
maybe it is safer as we are working on an element?
I don't seem to need the internalapi annotation
I got a version with the triple union working, but that's again using a try/catch
e
buildSerialDescriptor("Name", SerialKind.SEALED)
required
@Internal
, but I played around with it and it seems that
buildClassSerialDescriptor("Name")
works just fine, public API
updated to show off a few other things as well
b
thanks, this is really cool, I don't think I would have found all that by myself
oh you built even the Autosize part, I was making that one
You'll be an author on that lib if you want 😉
I thought about the "signal" in element, but I was worried this could appear in it by other means, but maybe I was over cautious
e
nah I was just checking that various things with
@SerialName
would work as expected
b
Thanks for your help, it make plots now!