diff --git a/tgbotapi.core/api/tgbotapi.core.api b/tgbotapi.core/api/tgbotapi.core.api index 7f0653eafbb..a8d77e93d2c 100644 --- a/tgbotapi.core/api/tgbotapi.core.api +++ b/tgbotapi.core/api/tgbotapi.core.api @@ -26132,11 +26132,8 @@ public abstract interface class dev/inmo/tgbotapi/types/update/abstracts/Update public abstract fun getUpdateId-4k5XoGU ()J } -public final class dev/inmo/tgbotapi/types/update/abstracts/UpdateDeserializationStrategy : kotlinx/serialization/DeserializationStrategy { +public final class dev/inmo/tgbotapi/types/update/abstracts/UpdateDeserializationStrategy : dev/inmo/tgbotapi/utils/serializers/CallbackCustomizableDeserializationStrategy { public static final field INSTANCE Ldev/inmo/tgbotapi/types/update/abstracts/UpdateDeserializationStrategy; - public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ldev/inmo/tgbotapi/types/update/abstracts/Update; - public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; - public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; } public final class dev/inmo/tgbotapi/types/update/abstracts/UpdateSerializerWithoutSerialization : kotlinx/serialization/KSerializer { @@ -26835,3 +26832,62 @@ public final class dev/inmo/tgbotapi/utils/passport/PassportDataDecryptionHandli public static synthetic fun doInDecryptionContextWithPKCS8Key$default (Ldev/inmo/tgbotapi/types/passport/PassportData;Ljava/security/PrivateKey;Ljava/lang/String;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ljava/lang/Object; } +public class dev/inmo/tgbotapi/utils/serializers/CallbackCustomizableDeserializationStrategy : dev/inmo/tgbotapi/utils/serializers/CustomizableDeserializationStrategy { + public fun (Lkotlinx/serialization/descriptors/SerialDescriptor;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;)V + public synthetic fun (Lkotlinx/serialization/descriptors/SerialDescriptor;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun addUpdateDeserializationStrategy (Ldev/inmo/tgbotapi/utils/serializers/CustomizableDeserializationStrategy$JsonDeserializerStrategy;)Z + public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; + public fun getCustomDeserializationStrategies ()Ljava/util/Set; + public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; + protected final fun get_customDeserializationStrategies ()Ljava/util/LinkedHashSet; + public fun removeUpdateDeserializationStrategy (Ldev/inmo/tgbotapi/utils/serializers/CustomizableDeserializationStrategy$JsonDeserializerStrategy;)Z +} + +public class dev/inmo/tgbotapi/utils/serializers/CallbackCustomizableSerializationStrategy : dev/inmo/tgbotapi/utils/serializers/CustomizableSerializationStrategy { + public fun (Lkotlinx/serialization/descriptors/SerialDescriptor;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;)V + public synthetic fun (Lkotlinx/serialization/descriptors/SerialDescriptor;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun addUpdateSerializationStrategy (Ldev/inmo/tgbotapi/utils/serializers/CustomizableSerializationStrategy$CustomSerializerStrategy;)Z + public fun getCustomSerializationStrategies ()Ljava/util/Set; + public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; + protected final fun get_customSerializationStrategies ()Ljava/util/LinkedHashSet; + public fun removeUpdateSerializationStrategy (Ldev/inmo/tgbotapi/utils/serializers/CustomizableSerializationStrategy$CustomSerializerStrategy;)Z + public fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V +} + +public class dev/inmo/tgbotapi/utils/serializers/CallbacksCustomizableDeserializationStrategy : dev/inmo/tgbotapi/utils/serializers/CustomizableDeserializationStrategy, dev/inmo/tgbotapi/utils/serializers/CustomizableSerializationStrategy, dev/inmo/tgbotapi/utils/serializers/CustomizableSerializer { + public fun (Lkotlinx/serialization/descriptors/SerialDescriptor;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function3;)V + public synthetic fun (Lkotlinx/serialization/descriptors/SerialDescriptor;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function3;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun addUpdateDeserializationStrategy (Ldev/inmo/tgbotapi/utils/serializers/CustomizableDeserializationStrategy$JsonDeserializerStrategy;)Z + public fun addUpdateSerializationStrategy (Ldev/inmo/tgbotapi/utils/serializers/CustomizableSerializationStrategy$CustomSerializerStrategy;)Z + public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; + public fun getCustomDeserializationStrategies ()Ljava/util/Set; + public fun getCustomSerializationStrategies ()Ljava/util/Set; + public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; + public fun removeUpdateDeserializationStrategy (Ldev/inmo/tgbotapi/utils/serializers/CustomizableDeserializationStrategy$JsonDeserializerStrategy;)Z + public fun removeUpdateSerializationStrategy (Ldev/inmo/tgbotapi/utils/serializers/CustomizableSerializationStrategy$CustomSerializerStrategy;)Z + public fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V +} + +public abstract interface class dev/inmo/tgbotapi/utils/serializers/CustomizableDeserializationStrategy : kotlinx/serialization/DeserializationStrategy { + public abstract fun addUpdateDeserializationStrategy (Ldev/inmo/tgbotapi/utils/serializers/CustomizableDeserializationStrategy$JsonDeserializerStrategy;)Z + public abstract fun getCustomDeserializationStrategies ()Ljava/util/Set; + public abstract fun removeUpdateDeserializationStrategy (Ldev/inmo/tgbotapi/utils/serializers/CustomizableDeserializationStrategy$JsonDeserializerStrategy;)Z +} + +public abstract interface class dev/inmo/tgbotapi/utils/serializers/CustomizableDeserializationStrategy$JsonDeserializerStrategy { + public abstract fun deserializeOrNull (Lkotlinx/serialization/json/JsonElement;)Ldev/inmo/micro_utils/common/Optional; +} + +public abstract interface class dev/inmo/tgbotapi/utils/serializers/CustomizableSerializationStrategy : kotlinx/serialization/SerializationStrategy { + public abstract fun addUpdateSerializationStrategy (Ldev/inmo/tgbotapi/utils/serializers/CustomizableSerializationStrategy$CustomSerializerStrategy;)Z + public abstract fun getCustomSerializationStrategies ()Ljava/util/Set; + public abstract fun removeUpdateSerializationStrategy (Ldev/inmo/tgbotapi/utils/serializers/CustomizableSerializationStrategy$CustomSerializerStrategy;)Z +} + +public abstract interface class dev/inmo/tgbotapi/utils/serializers/CustomizableSerializationStrategy$CustomSerializerStrategy { + public abstract fun optionallySerialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)Z +} + +public abstract interface class dev/inmo/tgbotapi/utils/serializers/CustomizableSerializer : dev/inmo/tgbotapi/utils/serializers/CustomizableDeserializationStrategy, dev/inmo/tgbotapi/utils/serializers/CustomizableSerializationStrategy, kotlinx/serialization/KSerializer { +} + diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/update/abstracts/Update.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/update/abstracts/Update.kt index 6409c164a60..c4891cedd8c 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/update/abstracts/Update.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/update/abstracts/Update.kt @@ -49,8 +49,8 @@ object UpdateSerializerWithoutSerialization : KSerializer { * @see kotlinx.serialization.json.Json.parse */ object UpdateDeserializationStrategy : CallbackCustomizableDeserializationStrategy( - JsonElement.serializer().descriptor, - { _, jsonElement -> + descriptor = JsonElement.serializer().descriptor, + defaultDeserializeCallback = { _, jsonElement -> nonstrictJsonFormat.decodeFromJsonElement( RawUpdate.serializer(), jsonElement!! @@ -58,7 +58,7 @@ object UpdateDeserializationStrategy : CallbackCustomizableDeserializationStrate jsonElement ) }, - { it, _, jsonElement -> + fallbackDeserialization = { it, _, jsonElement -> UnknownUpdate( UpdateId((jsonElement as? JsonObject) ?.get(updateIdField) ?.jsonPrimitive ?.longOrNull ?: -1L), jsonElement!!, diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/utils/serializers/CustomizableDeserializationStrategy.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/utils/serializers/CustomizableDeserializationStrategy.kt index c29c2323815..c65cdde7205 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/utils/serializers/CustomizableDeserializationStrategy.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/utils/serializers/CustomizableDeserializationStrategy.kt @@ -1,5 +1,7 @@ package dev.inmo.tgbotapi.utils.serializers +import dev.inmo.micro_utils.common.Optional +import dev.inmo.micro_utils.common.onPresented import dev.inmo.tgbotapi.types.update.RawUpdate import dev.inmo.tgbotapi.types.update.abstracts.Update import dev.inmo.tgbotapi.types.update.abstracts.UpdateDeserializationStrategy.deserialize @@ -11,7 +13,7 @@ import kotlinx.serialization.json.JsonElement interface CustomizableDeserializationStrategy : DeserializationStrategy { fun interface JsonDeserializerStrategy { - fun deserializeOrNull(json: JsonElement): T? + fun deserializeOrNull(json: JsonElement): Optional } /** * Contains [JsonDeserializerStrategy] which will be used in [deserialize] method when standard @@ -48,18 +50,27 @@ open class CallbackCustomizableDeserializationStrategy( override val customDeserializationStrategies: Set> get() = _customDeserializationStrategies.toSet() + /** + * Trying to get [JsonElement] if [decoder] is [JsonDecoder]. Then it will use [defaultDeserializeCallback] to + * deserialize data. In case if [defaultDeserializeCallback] will throw exception it will firstly try to deserialize + * data by strategies from [customDeserializationStrategies] and, if no one will return presented data in [Optional] + * it will use [fallbackDeserialization] as last option to deserialize data + */ override fun deserialize(decoder: Decoder): T { val jsonDecoder = decoder as? JsonDecoder val jsonElement = jsonDecoder ?.decodeJsonElement() return runCatching { defaultDeserializeCallback(decoder, jsonElement) - }.onFailure { - return (jsonElement ?.let { - customDeserializationStrategies.firstNotNullOfOrNull { - it.deserializeOrNull(jsonElement) + }.getOrElse { + (jsonElement ?.let { + customDeserializationStrategies.forEach { + it.deserializeOrNull(jsonElement).onPresented { + return@deserialize it + } } - }) ?: fallbackDeserialization(it, decoder, jsonElement) - }.getOrThrow() + }) + fallbackDeserialization(it, decoder, jsonElement) + } } /** diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/utils/serializers/CustomizableSerializationStrategy.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/utils/serializers/CustomizableSerializationStrategy.kt index 9a81bd64e46..7c0c00bc792 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/utils/serializers/CustomizableSerializationStrategy.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/utils/serializers/CustomizableSerializationStrategy.kt @@ -34,6 +34,11 @@ interface CustomizableSerializationStrategy : SerializationStrategy { ): Boolean } +/** + * @param defaultSerializeCallback Default way of serialization + * @param fallbackSerialization Fallback way which will be used in case when [defaultSerializeCallback] and [customSerializationStrategies] + * were unable to serialize data + */ open class CallbackCustomizableSerializationStrategy( override val descriptor: SerialDescriptor, private val defaultSerializeCallback: (encoder: Encoder, value: T) -> Unit, @@ -48,13 +53,23 @@ open class CallbackCustomizableSerializationStrategy( override val customSerializationStrategies: Set> get() = _customSerializationStrategies.toSet() + /** + * Trying to serialize data by [defaultSerializeCallback]. If [defaultSerializeCallback] it will try to use each + * strategy from [customSerializationStrategies] until one of them will return true (means, serialized). If there + * are no any strategy success serialization and [defaultSerializeCallback] thrown exception will be used + * [fallbackSerialization] callback + */ override fun serialize(encoder: Encoder, value: T) { runCatching { defaultSerializeCallback(encoder, value) - }.onFailure { - customSerializationStrategies.firstOrNull() { - it.optionallySerialize(encoder, value) - } ?: fallbackSerialization(it, encoder, value) + }.getOrElse { + customSerializationStrategies.forEach { + if (it.optionallySerialize(encoder, value)) { + return@getOrElse + } + } + // next line will be called onle in case all + fallbackSerialization(it, encoder, value) } } diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/utils/serializers/CustomizableSerializer.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/utils/serializers/CustomizableSerializer.kt index 4a386b25a3d..60d9db80b69 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/utils/serializers/CustomizableSerializer.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/utils/serializers/CustomizableSerializer.kt @@ -1,20 +1,16 @@ package dev.inmo.tgbotapi.utils.serializers -import dev.inmo.tgbotapi.types.update.RawUpdate -import dev.inmo.tgbotapi.types.update.abstracts.Update -import dev.inmo.tgbotapi.types.update.abstracts.UpdateDeserializationStrategy.deserialize -import kotlinx.serialization.DeserializationStrategy import kotlinx.serialization.KSerializer -import kotlinx.serialization.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 -interface CustomizableSerializer : KSerializer, CustomizableSerializationStrategy, CustomizableDeserializationStrategy { -} +interface CustomizableSerializer : KSerializer, CustomizableSerializationStrategy, CustomizableDeserializationStrategy +/** + * Combines [CallbackCustomizableSerializationStrategy] and [CallbackCustomizableDeserializationStrategy] + */ open class CallbacksCustomizableDeserializationStrategy( override val descriptor: SerialDescriptor, defaultDeserializeCallback: (decoder: Decoder, jsonElement: JsonElement?) -> T,