mirror of
https://github.com/InsanusMokrassar/TelegramBotAPI.git
synced 2024-11-09 09:53:47 +00:00
add common customizable serializer
This commit is contained in:
parent
d7e9c6a3a1
commit
c03440c353
@ -7,6 +7,7 @@ import dev.inmo.tgbotapi.types.updateIdField
|
||||
import dev.inmo.tgbotapi.utils.RiskFeature
|
||||
import dev.inmo.tgbotapi.utils.decodeDataAndJson
|
||||
import dev.inmo.tgbotapi.utils.nonstrictJsonFormat
|
||||
import dev.inmo.tgbotapi.utils.serializers.CallbackCustomizableDeserializationStrategy
|
||||
import kotlinx.serialization.*
|
||||
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
@ -47,52 +48,21 @@ object UpdateSerializerWithoutSerialization : KSerializer<Update> {
|
||||
* @see StringFormat.parse
|
||||
* @see kotlinx.serialization.json.Json.parse
|
||||
*/
|
||||
object UpdateDeserializationStrategy : DeserializationStrategy<Update> {
|
||||
private val _customDeserializationStrategies = LinkedHashSet<JsonDeserializerStrategy>()
|
||||
|
||||
/**
|
||||
* Contains [JsonDeserializerStrategy] which will be used in [deserialize] method when standard
|
||||
* [RawUpdate] serializer will be unable to create [RawUpdate] (and [Update] as well)
|
||||
*/
|
||||
val customDeserializationStrategies: Set<JsonDeserializerStrategy>
|
||||
get() = _customDeserializationStrategies.toSet()
|
||||
fun interface JsonDeserializerStrategy {
|
||||
fun deserializeOrNull(json: JsonElement): Update?
|
||||
}
|
||||
|
||||
override val descriptor: SerialDescriptor = JsonElement.serializer().descriptor
|
||||
|
||||
override fun deserialize(decoder: Decoder): Update {
|
||||
val asJson = JsonElement.serializer().deserialize(decoder)
|
||||
return runCatching {
|
||||
object UpdateDeserializationStrategy : CallbackCustomizableDeserializationStrategy<Update>(
|
||||
JsonElement.serializer().descriptor,
|
||||
{ _, jsonElement ->
|
||||
nonstrictJsonFormat.decodeFromJsonElement(
|
||||
RawUpdate.serializer(),
|
||||
asJson
|
||||
jsonElement!!
|
||||
).asUpdate(
|
||||
asJson
|
||||
jsonElement
|
||||
)
|
||||
}.getOrElse {
|
||||
customDeserializationStrategies.firstNotNullOfOrNull {
|
||||
it.deserializeOrNull(asJson)
|
||||
} ?: UnknownUpdate(
|
||||
UpdateId((asJson as? JsonObject) ?.get(updateIdField) ?.jsonPrimitive ?.longOrNull ?: -1L),
|
||||
asJson,
|
||||
},
|
||||
{ it, _, jsonElement ->
|
||||
UnknownUpdate(
|
||||
UpdateId((jsonElement as? JsonObject) ?.get(updateIdField) ?.jsonPrimitive ?.longOrNull ?: -1L),
|
||||
jsonElement!!,
|
||||
it
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adding [deserializationStrategy] into [customDeserializationStrategies] for using in case of unknown update
|
||||
*/
|
||||
fun addUpdateDeserializationStrategy(
|
||||
deserializationStrategy: JsonDeserializerStrategy
|
||||
) = _customDeserializationStrategies.add(deserializationStrategy)
|
||||
|
||||
/**
|
||||
* Removing [deserializationStrategy] from [customDeserializationStrategies]
|
||||
*/
|
||||
fun removeUpdateDeserializationStrategy(
|
||||
deserializationStrategy: JsonDeserializerStrategy
|
||||
) = _customDeserializationStrategies.remove(deserializationStrategy)
|
||||
}
|
||||
)
|
||||
|
@ -0,0 +1,78 @@
|
||||
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.descriptors.SerialDescriptor
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.json.JsonDecoder
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
|
||||
interface CustomizableDeserializationStrategy<T> : DeserializationStrategy<T> {
|
||||
fun interface JsonDeserializerStrategy<T> {
|
||||
fun deserializeOrNull(json: JsonElement): T?
|
||||
}
|
||||
/**
|
||||
* Contains [JsonDeserializerStrategy] which will be used in [deserialize] method when standard
|
||||
* [RawUpdate] serializer will be unable to create [RawUpdate] (and [Update] as well)
|
||||
*/
|
||||
val customDeserializationStrategies: Set<JsonDeserializerStrategy<T>>
|
||||
|
||||
/**
|
||||
* Adding [deserializationStrategy] into [customDeserializationStrategies] for using in case of unknown update
|
||||
*/
|
||||
fun addUpdateDeserializationStrategy(
|
||||
deserializationStrategy: JsonDeserializerStrategy<T>
|
||||
): Boolean
|
||||
|
||||
/**
|
||||
* Removing [deserializationStrategy] from [customDeserializationStrategies]
|
||||
*/
|
||||
fun removeUpdateDeserializationStrategy(
|
||||
deserializationStrategy: JsonDeserializerStrategy<T>
|
||||
): Boolean
|
||||
}
|
||||
|
||||
open class CallbackCustomizableDeserializationStrategy<T>(
|
||||
override val descriptor: SerialDescriptor,
|
||||
private val defaultDeserializeCallback: (decoder: Decoder, jsonElement: JsonElement?) -> T,
|
||||
private val fallbackDeserialization: (initialException: Throwable, decoder: Decoder, jsonElement: JsonElement?) -> T = { initialException, _, _ -> throw initialException }
|
||||
) : CustomizableDeserializationStrategy<T> {
|
||||
protected val _customDeserializationStrategies = LinkedHashSet<CustomizableDeserializationStrategy.JsonDeserializerStrategy<T>>()
|
||||
|
||||
/**
|
||||
* Contains [JsonDeserializerStrategy] which will be used in [deserialize] method when standard
|
||||
* [RawUpdate] serializer will be unable to create [RawUpdate] (and [Update] as well)
|
||||
*/
|
||||
override val customDeserializationStrategies: Set<CustomizableDeserializationStrategy.JsonDeserializerStrategy<T>>
|
||||
get() = _customDeserializationStrategies.toSet()
|
||||
|
||||
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)
|
||||
}
|
||||
}) ?: fallbackDeserialization(it, decoder, jsonElement)
|
||||
}.getOrThrow()
|
||||
}
|
||||
|
||||
/**
|
||||
* Adding [deserializationStrategy] into [customDeserializationStrategies] for using in case of unknown update
|
||||
*/
|
||||
override fun addUpdateDeserializationStrategy(
|
||||
deserializationStrategy: CustomizableDeserializationStrategy.JsonDeserializerStrategy<T>
|
||||
): Boolean = _customDeserializationStrategies.add(deserializationStrategy)
|
||||
|
||||
/**
|
||||
* Removing [deserializationStrategy] from [customDeserializationStrategies]
|
||||
*/
|
||||
override fun removeUpdateDeserializationStrategy(
|
||||
deserializationStrategy: CustomizableDeserializationStrategy.JsonDeserializerStrategy<T>
|
||||
): Boolean = _customDeserializationStrategies.remove(deserializationStrategy)
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
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.SerializationStrategy
|
||||
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.encoding.Encoder
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
|
||||
interface CustomizableSerializationStrategy<T> : SerializationStrategy<T> {
|
||||
fun interface CustomSerializerStrategy<T> {
|
||||
fun optionallySerialize(encoder: Encoder, value: T): Boolean
|
||||
}
|
||||
/**
|
||||
* Contains [CustomSerializerStrategy] which will be used in [Serialize] method when standard
|
||||
* [RawUpdate] serializer will be unable to create [RawUpdate] (and [Update] as well)
|
||||
*/
|
||||
val customSerializationStrategies: Set<CustomSerializerStrategy<T>>
|
||||
|
||||
/**
|
||||
* Adding [deserializationStrategy] into [customSerializationStrategies] for using in case of unknown update
|
||||
*/
|
||||
fun addUpdateSerializationStrategy(
|
||||
deserializationStrategy: CustomSerializerStrategy<T>
|
||||
): Boolean
|
||||
|
||||
/**
|
||||
* Removing [deserializationStrategy] from [customSerializationStrategies]
|
||||
*/
|
||||
fun removeUpdateSerializationStrategy(
|
||||
deserializationStrategy: CustomSerializerStrategy<T>
|
||||
): Boolean
|
||||
}
|
||||
|
||||
open class CallbackCustomizableSerializationStrategy<T>(
|
||||
override val descriptor: SerialDescriptor,
|
||||
private val defaultSerializeCallback: (encoder: Encoder, value: T) -> Unit,
|
||||
private val fallbackSerialization: (initialException: Throwable, encoder: Encoder, value: T) -> T = { initialException, _, _ -> throw initialException }
|
||||
) : CustomizableSerializationStrategy<T> {
|
||||
protected val _customSerializationStrategies = LinkedHashSet<CustomizableSerializationStrategy.CustomSerializerStrategy<T>>()
|
||||
|
||||
/**
|
||||
* Contains [JsonSerializerStrategy] which will be used in [deserialize] method when standard
|
||||
* [RawUpdate] serializer will be unable to create [RawUpdate] (and [Update] as well)
|
||||
*/
|
||||
override val customSerializationStrategies: Set<CustomizableSerializationStrategy.CustomSerializerStrategy<T>>
|
||||
get() = _customSerializationStrategies.toSet()
|
||||
|
||||
override fun serialize(encoder: Encoder, value: T) {
|
||||
runCatching {
|
||||
defaultSerializeCallback(encoder, value)
|
||||
}.onFailure {
|
||||
customSerializationStrategies.firstOrNull() {
|
||||
it.optionallySerialize(encoder, value)
|
||||
} ?: fallbackSerialization(it, encoder, value)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adding [deserializationStrategy] into [customSerializationStrategies] for using in case of unknown update
|
||||
*/
|
||||
override fun addUpdateSerializationStrategy(
|
||||
deserializationStrategy: CustomizableSerializationStrategy.CustomSerializerStrategy<T>
|
||||
): Boolean = _customSerializationStrategies.add(deserializationStrategy)
|
||||
|
||||
/**
|
||||
* Removing [deserializationStrategy] from [customSerializationStrategies]
|
||||
*/
|
||||
override fun removeUpdateSerializationStrategy(
|
||||
deserializationStrategy: CustomizableSerializationStrategy.CustomSerializerStrategy<T>
|
||||
): Boolean = _customSerializationStrategies.remove(deserializationStrategy)
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
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<T> : KSerializer<T>, CustomizableSerializationStrategy<T>, CustomizableDeserializationStrategy<T> {
|
||||
}
|
||||
|
||||
open class CallbacksCustomizableDeserializationStrategy<T>(
|
||||
override val descriptor: SerialDescriptor,
|
||||
defaultDeserializeCallback: (decoder: Decoder, jsonElement: JsonElement?) -> T,
|
||||
defaultSerializeCallback: (encoder: Encoder, value: T) -> Unit,
|
||||
fallbackDeserialization: (initialException: Throwable, decoder: Decoder, jsonElement: JsonElement?) -> T = { initialException, _, _ -> throw initialException },
|
||||
fallbackSerialization: (initialException: Throwable, encoder: Encoder, value: T) -> T = { initialException, _, _ -> throw initialException }
|
||||
) : CustomizableSerializer<T>,
|
||||
CustomizableSerializationStrategy<T> by CallbackCustomizableSerializationStrategy(descriptor, defaultSerializeCallback, fallbackSerialization),
|
||||
CustomizableDeserializationStrategy<T> by CallbackCustomizableDeserializationStrategy(descriptor, defaultDeserializeCallback, fallbackDeserialization){
|
||||
}
|
Loading…
Reference in New Issue
Block a user