All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
internal.data.serializerHelper.kt Maven / Gradle / Ivy
/*
* Copyright 2019-2021 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
@file:Suppress("unused")
package net.mamoe.mirai.console.internal.data
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.InternalSerializationApi
import kotlinx.serialization.KSerializer
import kotlinx.serialization.builtins.*
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.serializer
import net.mamoe.yamlkt.YamlDynamicSerializer
import net.mamoe.yamlkt.YamlNullableDynamicSerializer
import java.lang.reflect.Modifier
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.ConcurrentMap
import kotlin.reflect.KClass
import kotlin.reflect.KType
/**
* Copied from kotlinx.serialization, modifications are marked with "/* mamoe modify */"
* Copyright 2017-2020 JetBrains s.r.o.
*/
@OptIn(InternalSerializationApi::class, ExperimentalSerializationApi::class)
@Suppress(
"UNCHECKED_CAST",
"NO_REFLECTION_IN_CLASS_PATH",
"UNSUPPORTED",
"INVISIBLE_MEMBER",
"INVISIBLE_REFERENCE",
"IMPLICIT_CAST_TO_ANY"
)
internal fun serializerMirai(type: KType): KSerializer {
fun serializerByKTypeImpl(type: KType): KSerializer {
val rootClass = type.classifierAsKClass()
val typeArguments = type.arguments
.map { requireNotNull(it.type) { "Star projections in type arguments are not allowed, but had $type" } }
return when {
typeArguments.isEmpty() -> rootClass.serializer()
else -> {
val serializers = typeArguments
.map(::serializerMirai)
// Array is not supported, see KT-32839
when (rootClass) {
List::class, MutableList::class, ArrayList::class -> ListSerializer(serializers[0])
HashSet::class -> SetSerializer(serializers[0])
Set::class, MutableSet::class, LinkedHashSet::class -> SetSerializer(serializers[0])
HashMap::class -> MapSerializer(serializers[0], serializers[1])
ConcurrentHashMap::class, ConcurrentMap::class -> MapSerializer(serializers[0], serializers[1]).map(
serializer = { HashMap(it as Map<*, *>) },
deserializer = { ConcurrentHashMap(it) }
)
Map::class, MutableMap::class, LinkedHashMap::class -> MapSerializer(serializers[0], serializers[1])
Map.Entry::class -> MapEntrySerializer(serializers[0], serializers[1])
Pair::class -> PairSerializer(serializers[0], serializers[1])
Triple::class -> TripleSerializer(serializers[0], serializers[1], serializers[2])
/* mamoe modify */ Any::class -> if (type.isMarkedNullable) YamlNullableDynamicSerializer else YamlDynamicSerializer
else -> {
if (rootClass.java.isArray) {
return ArraySerializer(
typeArguments[0].classifier as KClass,
serializers[0]
).cast()
}
requireNotNull(rootClass.constructSerializerForGivenTypeArgs(*serializers.toTypedArray())) {
"Can't find a method to construct serializer for type ${rootClass.simpleName}. " +
"Make sure this class is marked as @Serializable or provide serializer explicitly."
}
}
}
}
}.cast()
}
val result = serializerByKTypeImpl(type)
return if (type.isMarkedNullable) result.nullable else result.cast()
}
/**
* Copied from kotlinx.serialization, modifications are marked with "/* mamoe modify */"
* Copyright 2017-2020 JetBrains s.r.o.
*/
@Suppress(
"UNCHECKED_CAST",
"NO_REFLECTION_IN_CLASS_PATH",
"UNSUPPORTED",
"INVISIBLE_MEMBER",
"INVISIBLE_REFERENCE",
"IMPLICIT_CAST_TO_ANY"
)
private fun KClass.constructSerializerForGivenTypeArgs(vararg args: KSerializer): KSerializer? {
val jClass = this.java
// Search for serializer defined on companion object.
val companion =
jClass.declaredFields.singleOrNull { it.name == "Companion" }?.apply { isAccessible = true }?.get(null)
if (companion != null) {
val serializer = companion.javaClass.methods
.find { method ->
method.name == "serializer" && method.parameterTypes.size == args.size && method.parameterTypes.all { it == KSerializer::class.java }
}
?.invoke(companion, *args) as? KSerializer
if (serializer != null) return serializer
}
// Check whether it's serializable object
findObjectSerializer(jClass)?.let { return it }
// Search for default serializer if no serializer is defined in companion object.
return try {
jClass.declaredClasses.singleOrNull { it.simpleName == ("\$serializer") }
?.getField("INSTANCE")?.get(null) as? KSerializer
} catch (e: NoSuchFieldException) {
null
}
}
private fun findObjectSerializer(jClass: Class): KSerializer? {
// Check it is an object without using kotlin-reflect
val field =
jClass.declaredFields.singleOrNull { it.name == "INSTANCE" && it.type == jClass && Modifier.isStatic(it.modifiers) }
?: return null
// Retrieve its instance and call serializer()
val instance = field.get(null)
val method =
jClass.methods.singleOrNull { it.name == "serializer" && it.parameters.isEmpty() && it.returnType == KSerializer::class.java }
?: return null
val result = method.invoke(instance)
@Suppress("UNCHECKED_CAST")
return result as? KSerializer
}
internal inline fun KSerializer.bind(
crossinline setter: (E) -> Unit,
crossinline getter: () -> E
): KSerializer {
return object : KSerializer {
override val descriptor: SerialDescriptor get() = [email protected]
override fun deserialize(decoder: Decoder): E = [email protected] (decoder).also { setter(it) }
@Suppress("UNCHECKED_CAST")
override fun serialize(encoder: Encoder, value: E) =
[email protected] (encoder, getter())
}
}
internal inline fun KSerializer.map(
crossinline serializer: (R) -> E,
crossinline deserializer: (E) -> R
): KSerializer {
return object : KSerializer {
override val descriptor: SerialDescriptor get() = [email protected]
override fun deserialize(decoder: Decoder): R = [email protected] (decoder).let(deserializer)
override fun serialize(encoder: Encoder, value: R) = [email protected] (encoder, value.let(serializer))
}
}