0

I'm trying to deserialize a data class to be sent through a WebSocket with the Kotlinx.serialization library using Ktor, but I'm having some issues, the serializer just deserializes the first value of the data class. I'm using Kmongo for the connection with the database so I'm using the @BsonId annotation for making MongoDb that that property is the id.

I leave here the data class.

@Serializable
data class Kayak(
    @Serializable(ObjectIdSerializer::class) @BsonId val id: ObjectId = ObjectId(),
    val available: Boolean = true,
    val type: TypeOfKayak = TypeOfKayak.Single,
    val reservesIds: List<String> = emptyList()
)

As the serializer doesn't know how to serialize and deserialize the ObjectId data type I've made it by myself and it's the next:

fun String.toObjectId(): ObjectId = ObjectId(this)


object ObjectIdSerializer : KSerializer<ObjectId> {
    override val descriptor = PrimitiveSerialDescriptor("ObjectId", PrimitiveKind.STRING)

    override fun serialize(encoder: Encoder, value: ObjectId) {
        encoder.encodeString(value.toHexString())
    }

    override fun deserialize(decoder: Decoder): ObjectId {
        val stringValue = decoder.decodeString()
        try {
            return ObjectId(stringValue)
        } catch (e: IllegalArgumentException) {
            throw SerializationException("Failed to deserialize ObjectId: $stringValue", e)
        }
    }
}

The expected output would be like this:

[
  {
    "id": "648b2fa450b8031dadaf62a8",
    "available": true,
    "type": "Single",
    "reservesIds": [
      "abc123",
      "def456"
    ]
  },
  {
    "id": "648b2fa450b8031dadaf62a9",
    "available": false,
    "type": "Double",
    "reservesIds": [
      "xyz789"
    ]
  }
]

but instead it's like this:

{
  "id": "648b2fa450b8031dadaf62a8"
}

I tried by using the next things:

private val json = Json {
    prettyPrint = true
    ignoreUnknownKeys = true
}

val message = json.encodeToString(kayaksDb.getAllKayaks())
val message = json.encodeToString<List<Kayak>>(kayaksDb.getAllKayaks(), ListSerializer(Kayak.serializer()))

Anyways It's strange because when I just use in an endpoint the call.respond() function it works well, I leave here an example:

        get<KayaksRoutes> {
            call.respond(kayaksDataSource.getAllKayaks())
        }

the output is the next:

[
  {
    "id": "648b2fa450b8031dadaf62a8",
    "available": true,
    "type": "Single",
    "reservesIds": []
  }
]

so I think I'm doing something bad at the moment of sending the data/parsing it to the WebSocket.

Thank you guys for the help!

Bobby ESP
  • 15
  • 5
  • Set `encodeDefaults` to true in your Json setup, or mark the individual properties with `@EncodeDefault`. [See here.](https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/basic-serialization.md#defaults-are-not-encoded-by-default) – Tenfour04 Jun 15 '23 at 20:17
  • OMG YOU SAVED ME. Really really thanks, it worked! – Bobby ESP Jun 15 '23 at 20:33

1 Answers1

0

The problem was fixed by adding encodeDefaults to the Json options builder and setting it to true:

private val json = Json {
    prettyPrint = true
    ignoreUnknownKeys = true
    encodeDefaults = true
}

Answered by Tenfour04, really thanks mate!

Bobby ESP
  • 15
  • 5