Reputation: 757
I'm using external API in the app, while deserialisation is done with Kotlinx Serialization package, i'm facing issues when api result is Array of Int for multiple values and primitive int for single value. How can i avoid crash in this process. Is there better approach to avoid crashes or creating data classes
ex:
import kotlinx.serialization.Serializable
@Serializable
data class Bookings (val slots: List<Int>)
when slots is having single value API returns {slots: 1}
when slots is having multiple value API return { slots: [1,2,3,4]}
Upvotes: 4
Views: 1006
Reputation: 15309
I updated @Andrei's answer for 2021 since the class and method names have changed a bit since 2019:
import kotlinx.serialization.*
import kotlinx.serialization.json.*
import kotlinx.serialization.encoding.Decoder
@Serializable(with = BookingsSerializer::class)
data class Bookings(val slots: List<Int>)
@Serializer(forClass = Bookings::class)
object BookingsSerializer : KSerializer<Bookings> {
override fun deserialize(decoder: Decoder): Bookings {
val json = (decoder as JsonDecoder).decodeJsonElement().jsonObject
return Bookings(parseSlots(json))
}
private fun parseSlots(json: JsonObject): List<Int> {
val slotsJson = json["slots"] ?: return emptyList()
return try {
slotsJson.jsonArray.map { it.jsonPrimitive.int }
} catch (e: Exception) {
listOf(slotsJson.jsonPrimitive.int)
}
}
}
val json = """{"slots": 1}"""
val result = Json.decodeFromString<Bookings>(json)
println(result.toString()) // prints Bookings(slots=[1])
Upvotes: 4
Reputation: 8432
It can be done with custom serializer:
import kotlinx.serialization.*
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonInput
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.int
@Serializable(with = BookingsSerializer::class)
data class Bookings(val slots: List<Int>)
@Serializer(forClass = Bookings::class)
object BookingsSerializer : KSerializer<Bookings> {
override fun deserialize(decoder: Decoder): Bookings {
val json = (decoder as JsonInput).decodeJson().jsonObject
return Bookings(parseSlots(json))
}
private fun parseSlots(json: JsonObject): List<Int> {
val slotsJson = json["slots"] ?: return emptyList()
return try {
slotsJson.jsonArray.content.map { it.int }
} catch (e: Exception) {
listOf(slotsJson.int)
}
}
}
@ImplicitReflectionSerializer
fun main() {
val json = """{"slots": 1}"""
val result = Json.parse<Bookings>(json)
println(result) // prints Bookings(slots=[1])
}
Upvotes: 5