I found this 1+ year old comment while trying to d...
# serialization
p
I found this 1+ year old comment while trying to debug some Kotlin JVM serialization code I am working on: "Kotlin serialization is more like a serialization code generator than a serialization library. Most JSON libraries are more for reading/writing Json rather than generating it." Given the hassles I've had trying to configure Gradle to be happy with the documented use of Kotlin serialization, I'm thinking this comment is meant for my application and I should be looking to GSON or Jackson rather than a Kotlin solution. My app definitely wants a library type solution: given a class get the JSON representation as a string and vice versa. But while the former does not involve code generation, the latter might, so I'm confused. And my preferences are for a pure Kotlin solution if at all possible. Advice, as in "how would you approach this problem - keep troubleshooting or switch to Jackson or GSON"?
btw, I'll drill into more detail if I hear a consensus that Kotlin serialization is a perfectly good tool for solving this problem.
a
Kotlinx serialization has a different implementation to achieve the same goal. while that comment is true, its an implementation technique. Most libraries (including Gson and Jackson) do rely on reflection, while kotlinx serialization doesn't. Thanks to code generation. Another huge advantage for kotlinx serialization is that, its multiplatform. If all you need is to serialize jvm classes you can choose to pick any among those. While they all have the same goal, each has a different implementation
p
Is there a chance that Kotlin serialization is ONLY for KMP? I'm guessing yes but would love to see that refuted.
m
You could also try mine: https://github.com/fluidsonic/fluid-json BUT it's using Kapt for code generation, not a compiler plugin, and is JVM-only for now.
a
Nothing can be KMP only. Every KMP has to jabe at least one target. and if jvm is one of target then the whole lib should work on jvm as a pure jvm lib
n
I would say that your use case is perfect for kotlinx serialization. All you need to do is add an @Serializable annotation, and your class can be serialized. Creating a Json serializer is easy (
val json = Json{ }
), and then you can simply
val classAsJson = json.encodeToString(MyClass.serializer(), myClassInstance)
and the corresponding
decodeFromString
to load the string as a class. This is valid JSON that any library can deserialize
c
The main difference you’ll find using Kotlinx.serialization vs a runtime library-type solution is that you have to be explicit with your intention. A library-type is able to use reflection to determine the class to deserialize, while you’ll have to pass the generated
.serializer()
to the kotlinx library to do the same. And it’s similar for polymorphic serialization, a library can use reflection to determine which subclass to create, while you’ll need to manually set up a
serializerModule
for kotlinx to do that.
I actually prefer the explicitness of Kotlinx.serialization, but it is also a bit cumbersome and you may prefer the simplicity of a library-type. Also, something that might catch you off-guard is the fact that JVM libraries like Jackson and GSON do not understand some Kotlin semantics like default parameters, and so may deserialize a property with a different default value, or even null into a non-null property. Kotlinx.serialization doesn’t have this particular problem.
m
What I don't like about kotlinx here is that I can't just see, copy and debug generated code. That made it really difficult to solve issues or understand certain behavior. But that was months ago, maybe it's better by now.
a
While what @Casey Brooks says is true. Starting from 1.0.0-RC you explicitly don't need to pass serializers in simple cases. Only when dealing with generics and other complicated stuffs
p
@Casey Brooks I have implemented Kotlinx serialization for an LSP client. LSP has a high degree of polymorphic serialization and Kotlinx serialization does a very nice job of serializing/deserializing within a single process or across two processes which are using compatible serialization techniques. Unfortunately from my app's perspective the server is a black box. When serializing a polymorphic object, I can eliminate the "type" discriminant when encoding and keep the black box server happy but I have not yet figured out how to do this for a deep hierarchy of polymorphic objects. For example, using `Json.encodeToString(SealedRequestMessageSerializer, request)`the "type discriminant is removed from the top level but not the nested fields giving: """{"jsonrpc":"2.0","id":{"type":"com.pajato.edgar.lsp4k.NumberId","value":1,"valueAsInt":1},"method":"initialize","params":{"type":"com.pajat...""", i.e. the nested fields still have "type" discriminants being passed to the black box server which complains loudly about the "type" fields. So far, I do not see a way to filter out all the type discriminants in one fell swoop. Is there a simple solution to this issue? If I can crack this nut, I should have the beginnings of a very nice Kotlin SDK for LSP clients and servers, fwiw.