I'm getting json data from server API to Android app (Kotlin Serialization + Retrofit)
I need to parse a Json with field errors
. The issue is the structure of this field.
If there are no errors I get empty array:
"errors":[]
But if there are some errors, I get this structure, like a Map with dynamic key:
"errors":{"kode":"The kode field do not exist."}
The question:
What type should I use for errors
field in my Serializable Kotlin data class to be able parse it in both cases?
If I use Map<String, String>
, it works only if there are some errors. For json with empty errors I get exception:
Unexpected JSON token at offset 86: Expected start of the object '{', but had '[' instead at path: $.errors
I tried to use KSerializer to return empty Map if cannot deserialize errors
as a Map
class TestDeserializer: KSerializer<Map<String, String>> {
private val delegateMapSerializer = MapSerializer(String.serializer(), String.serializer())
override val descriptor: SerialDescriptor
get() = SerialDescriptor("Errors", delegateMapSerializer.descriptor)
override fun deserialize(decoder: Decoder): Map<String, String> {
return try {
decoder.decodeSerializableValue(delegateMapSerializer)
} catch (e: Exception) {
emptyMap()
}
}
override fun serialize(encoder: Encoder, value: Map<String, String>) {
TODO("Not yet implemented")
}
}
And use it in my Kotlin data class:
@Serializable(with = TestDeserializer::class)
val errors: Map<String, String>
But probably did smth wrong, because still get the same JsonDecodingException
Found another way to create Deserializer that checks if json element is an array and replaces it with empty map.
class ErrorsDeserializer: JsonTransformingSerializer<Map<String, String>>(
MapSerializer(String.serializer(), String.serializer())
) {
override fun transformDeserialize(element: JsonElement): JsonElement {
if (element is JsonArray) return JsonObject(emptyMap())
return element
}
}
Use it for errors
in data class
@Serializable(with = ErrorsDeserializer::class)
val errors: Map<String, String> = emptyMap()