diff options
Diffstat (limited to 'wallet/src/main/java/net/taler/wallet/backend/WalletResponse.kt')
-rw-r--r-- | wallet/src/main/java/net/taler/wallet/backend/WalletResponse.kt | 90 |
1 files changed, 60 insertions, 30 deletions
diff --git a/wallet/src/main/java/net/taler/wallet/backend/WalletResponse.kt b/wallet/src/main/java/net/taler/wallet/backend/WalletResponse.kt index ab1ac80..3946457 100644 --- a/wallet/src/main/java/net/taler/wallet/backend/WalletResponse.kt +++ b/wallet/src/main/java/net/taler/wallet/backend/WalletResponse.kt @@ -19,26 +19,31 @@ package net.taler.wallet.backend import kotlinx.serialization.KSerializer import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable -import kotlinx.serialization.descriptors.PrimitiveKind.STRING -import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor +import kotlinx.serialization.builtins.MapSerializer +import kotlinx.serialization.builtins.serializer +import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Encoder import kotlinx.serialization.json.JsonDecoder +import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonObject -import org.json.JSONObject +import kotlinx.serialization.json.JsonPrimitive +import kotlinx.serialization.json.buildJsonObject +import kotlinx.serialization.json.jsonObject +import kotlinx.serialization.json.jsonPrimitive @Serializable sealed class WalletResponse<T> { @Serializable @SerialName("response") data class Success<T>( - val result: T + val result: T, ) : WalletResponse<T>() @Serializable @SerialName("error") data class Error<T>( - val error: TalerErrorInfo + val error: TalerErrorInfo, ) : WalletResponse<T>() fun onSuccess(block: (result: T) -> Unit): WalletResponse<T> { @@ -52,53 +57,78 @@ sealed class WalletResponse<T> { } } -@Serializable +@Serializable(with = TalerErrorInfoSerializer::class) data class TalerErrorInfo( // Numeric error code defined defined in the // GANA gnu-taler-error-codes registry. - val code: Int, + val code: TalerErrorCode, // English description of the error code. - val hint: String?, + val hint: String? = null, // English diagnostic message that can give details // for the instance of the error. - val message: String?, + val message: String? = null, - // Error details - @Serializable(JSONObjectDeserializer::class) - val details: JSONObject? + // Error extra details + val extra: Map<String, JsonElement> = mapOf(), ) { val userFacingMsg: String get() { return StringBuilder().apply { - append(code) - hint?.let { append(" (").append(it).append(")") } - message?.let { append(" ").append(it) } - details?.let { details -> - if (details.length() > 0) { - append("\n\n") - details.optJSONObject("errorResponse")?.let { errorResponse -> - append(errorResponse.optString("code")).append(" ") - append(errorResponse.optString("hint")) - } ?: append(details.toString(2)) + // If there's a hint in errorResponse, use it. + if (extra.containsKey("errorResponse")) { + val errorResponse = extra["errorResponse"]!!.jsonObject + if (errorResponse.containsKey("hint")) { + val hint = errorResponse["hint"]!!.jsonPrimitive.content + append(hint) } + } else { + // Otherwise, use the standard ones + hint?.let { append(it) } + message?.let { append(" ").append(it) } } }.toString() } + + fun getStringExtra(key: String): String? = + extra[key]?.jsonPrimitive?.content } -class JSONObjectDeserializer : KSerializer<JSONObject> { +class TalerErrorInfoSerializer : KSerializer<TalerErrorInfo> { + private val stringToJsonElementSerializer = MapSerializer(String.serializer(), JsonElement.serializer()) + + override val descriptor: SerialDescriptor + get() = stringToJsonElementSerializer.descriptor + + override fun deserialize(decoder: Decoder): TalerErrorInfo { + // Decoder -> JsonInput + require(decoder is JsonDecoder) + val json = decoder.json + val filtersMap = decoder.decodeSerializableValue(stringToJsonElementSerializer) + + val code = filtersMap["code"]?.let { + json.decodeFromJsonElement(TalerErrorCode.serializer(), it) + } ?: TalerErrorCode.UNKNOWN + val hint = filtersMap["hint"]?.let { + json.decodeFromJsonElement(String.serializer(), it) + } + val message = filtersMap["message"]?.let { + json.decodeFromJsonElement(String.serializer(), it) + } - override val descriptor = PrimitiveSerialDescriptor("JSONObjectDeserializer", STRING) + val knownKeys = setOf("code", "hint", "message") + val unknownFilters = filtersMap.filter { (key, _) -> !knownKeys.contains(key) } - override fun deserialize(decoder: Decoder): JSONObject { - val input = decoder as JsonDecoder - val tree = input.decodeJsonElement() as JsonObject - return JSONObject(tree.toString()) + return TalerErrorInfo(code, hint, message, unknownFilters) } - override fun serialize(encoder: Encoder, value: JSONObject) { - error("not supported") + override fun serialize(encoder: Encoder, value: TalerErrorInfo) { + encoder.encodeSerializableValue(JsonObject.serializer(), buildJsonObject { + put("code", JsonPrimitive(value.code.code)) + put("hint", JsonPrimitive(value.hint)) + put("message", JsonPrimitive(value.message)) + value.extra.forEach { (key, value) -> put(key, value) } + }) } } |