81 lines
2.7 KiB
Kotlin
81 lines
2.7 KiB
Kotlin
package dev.inmo.postssystem.features.roles.common
|
|
|
|
import kotlinx.serialization.*
|
|
import kotlinx.serialization.builtins.serializer
|
|
import kotlinx.serialization.descriptors.SerialDescriptor
|
|
import kotlinx.serialization.encoding.*
|
|
import kotlinx.serialization.json.*
|
|
|
|
@Polymorphic
|
|
interface Role {
|
|
companion object {
|
|
fun serializer(): KSerializer<Role> = RoleSerializer
|
|
}
|
|
}
|
|
|
|
@Serializable
|
|
data class UnknownRole(val originalJson: JsonElement) : Role
|
|
|
|
object RoleSerializer : KSerializer<Role> {
|
|
private val userRoleFormat = Json { ignoreUnknownKeys = true }
|
|
private const val keyField = "key"
|
|
private const val valueField = "value"
|
|
private val serializers = mutableMapOf<String, KSerializer<out Role>>()
|
|
override val descriptor: SerialDescriptor = String.serializer().descriptor
|
|
|
|
@OptIn(InternalSerializationApi::class)
|
|
override fun deserialize(decoder: Decoder): Role {
|
|
return if (decoder is JsonDecoder) {
|
|
val originalJson = decoder.decodeJsonElement().jsonObject
|
|
val type = originalJson[keyField]?.jsonPrimitive ?.content
|
|
return if (type == null || !serializers.containsKey(type)) {
|
|
UnknownRole(originalJson)
|
|
} else {
|
|
userRoleFormat.decodeFromJsonElement(
|
|
serializers.getValue(type),
|
|
originalJson[valueField] ?: buildJsonObject { }
|
|
)
|
|
}
|
|
} else {
|
|
val encoded = decoder.decodeString()
|
|
userRoleFormat.decodeFromString(this, encoded)
|
|
}
|
|
}
|
|
|
|
@InternalSerializationApi
|
|
private fun <T : Role> T.toJson(): JsonElement {
|
|
return userRoleFormat.encodeToJsonElement(this::class.serializer() as KSerializer<T>, this)
|
|
}
|
|
|
|
@OptIn(InternalSerializationApi::class)
|
|
override fun serialize(encoder: Encoder, value: Role) {
|
|
if (encoder is JsonEncoder) {
|
|
if (value is UnknownRole) {
|
|
encoder.encodeJsonElement(value.originalJson)
|
|
} else {
|
|
val valueSerializer = value::class.serializer()
|
|
val type = serializers.keys.first { serializers[it] == valueSerializer }
|
|
encoder.encodeJsonElement(
|
|
buildJsonObject {
|
|
put(keyField, type)
|
|
put(valueField, value.toJson())
|
|
}
|
|
)
|
|
}
|
|
} else {
|
|
encoder.encodeString(
|
|
userRoleFormat.encodeToString(this, value)
|
|
)
|
|
}
|
|
}
|
|
|
|
fun <T : Role> includeSerializer(
|
|
type: String,
|
|
kSerializer: KSerializer<T>
|
|
) { serializers[type] = kSerializer }
|
|
|
|
fun excludeSerializer(type: String) {
|
|
serializers.remove(type)
|
|
}
|
|
}
|