mirror of
https://github.com/InsanusMokrassar/TelegramBotAPI.git
synced 2024-11-22 00:03:48 +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.RiskFeature
|
||||||
import dev.inmo.tgbotapi.utils.decodeDataAndJson
|
import dev.inmo.tgbotapi.utils.decodeDataAndJson
|
||||||
import dev.inmo.tgbotapi.utils.nonstrictJsonFormat
|
import dev.inmo.tgbotapi.utils.nonstrictJsonFormat
|
||||||
|
import dev.inmo.tgbotapi.utils.serializers.CallbackCustomizableDeserializationStrategy
|
||||||
import kotlinx.serialization.*
|
import kotlinx.serialization.*
|
||||||
import kotlinx.serialization.descriptors.SerialDescriptor
|
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||||
import kotlinx.serialization.encoding.Decoder
|
import kotlinx.serialization.encoding.Decoder
|
||||||
@ -47,52 +48,21 @@ object UpdateSerializerWithoutSerialization : KSerializer<Update> {
|
|||||||
* @see StringFormat.parse
|
* @see StringFormat.parse
|
||||||
* @see kotlinx.serialization.json.Json.parse
|
* @see kotlinx.serialization.json.Json.parse
|
||||||
*/
|
*/
|
||||||
object UpdateDeserializationStrategy : DeserializationStrategy<Update> {
|
object UpdateDeserializationStrategy : CallbackCustomizableDeserializationStrategy<Update>(
|
||||||
private val _customDeserializationStrategies = LinkedHashSet<JsonDeserializerStrategy>()
|
JsonElement.serializer().descriptor,
|
||||||
|
{ _, jsonElement ->
|
||||||
/**
|
nonstrictJsonFormat.decodeFromJsonElement(
|
||||||
* Contains [JsonDeserializerStrategy] which will be used in [deserialize] method when standard
|
RawUpdate.serializer(),
|
||||||
* [RawUpdate] serializer will be unable to create [RawUpdate] (and [Update] as well)
|
jsonElement!!
|
||||||
*/
|
).asUpdate(
|
||||||
val customDeserializationStrategies: Set<JsonDeserializerStrategy>
|
jsonElement
|
||||||
get() = _customDeserializationStrategies.toSet()
|
)
|
||||||
fun interface JsonDeserializerStrategy {
|
},
|
||||||
fun deserializeOrNull(json: JsonElement): Update?
|
{ it, _, jsonElement ->
|
||||||
|
UnknownUpdate(
|
||||||
|
UpdateId((jsonElement as? JsonObject) ?.get(updateIdField) ?.jsonPrimitive ?.longOrNull ?: -1L),
|
||||||
|
jsonElement!!,
|
||||||
|
it
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
)
|
||||||
override val descriptor: SerialDescriptor = JsonElement.serializer().descriptor
|
|
||||||
|
|
||||||
override fun deserialize(decoder: Decoder): Update {
|
|
||||||
val asJson = JsonElement.serializer().deserialize(decoder)
|
|
||||||
return runCatching {
|
|
||||||
nonstrictJsonFormat.decodeFromJsonElement(
|
|
||||||
RawUpdate.serializer(),
|
|
||||||
asJson
|
|
||||||
).asUpdate(
|
|
||||||
asJson
|
|
||||||
)
|
|
||||||
}.getOrElse {
|
|
||||||
customDeserializationStrategies.firstNotNullOfOrNull {
|
|
||||||
it.deserializeOrNull(asJson)
|
|
||||||
} ?: UnknownUpdate(
|
|
||||||
UpdateId((asJson as? JsonObject) ?.get(updateIdField) ?.jsonPrimitive ?.longOrNull ?: -1L),
|
|
||||||
asJson,
|
|
||||||
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