I have a case where I need to deserialize JSON files whose format may differ depending on a `version...
s
I have a case where I need to deserialize JSON files whose format may differ depending on a
version
field in a
header
section. At first I though I could use a
sealed class
instance per version and https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/json.md#class-discriminator-for-polymorphism, but the problem is that the "discriminator" in this case is the
version
that is part of a different JSON hierarchy than the changing structures themselves. Is there a way to solve this with built-in means / annotations instead of going the route of manually writing custom deserializers?
a
can you share an example of the JSON?
s
It's basically like this:
Copy code
{
  "headers": [
    {
      "output_format_version": "2.0.0"
    }
  ],
  "files": [
    {
      // Different structure based on "output_format_version" above.
    }
 ]
}
But still the problem is that the property to select the (de-)serializer on is not part of the
JsonElement
I'm deserializing.
a
yes, that makes it more difficult. You’d have to use the content based serializer on the containing class
s
It'd work if there was a way to get to the root of the JSON hierarchy from a
JsonElement
, in order to access the header from here again...
a
so something like this
Copy code
@Serializable(with = SomeContentBasedSerializerForMyJsonContent::class)
sealed interface MyJsonContent {

  val files: List<FileType>

  class Version1 {
    val headers: List<>,
    override val files: List<FileTypeV1>,
  }
  class Version2 {
    val headers: List<>,
    override val files: List<FileTypeV2>,
  }
  class Version3 {
    val headers: List<>,
    override val files: List<FileTypeV3>,
  }
}

sealed interface FileType // just here for organisation, doesn't need to be @Serializable

class FileTypeV1 (....): FileType 
class FileTypeV2 (....): FileType 
class FileTypeV3 (....): FileType
you could also defer decoding the file types by using
val files: List<JsonObject>
, and then ‘properly’ decode them once the containing object (and the headers) are decoded. This would be nicer because there’s no custom serializers needed.
s
Yeah, that'd work, although I'm not a big fan of mixing purely
data class
based decoding with
JsonObject
decoding...
a
how big a fan are you of “if it’s stupid and it works it’s not stupid”? 😄
s
Not so much 😉
a
oh, in case there was a misunderstanding I wasn’t suggesting manually decoding JsonObjects. You can use Json.decodeFromJsonElement()
s
yes, thanks, that bit was clear.
I wonder whether I could use https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/serializers.md#contextual-serialization instead, and selecting the
SerializersModule
at runtime depending on the
output_format_version
... I'll experiment with that.