From 2e91ae0d7f8a94396de5f048fe1bea4420c45952 Mon Sep 17 00:00:00 2001
From: Him188 <Him188@mamoe.net>
Date: Wed, 3 Feb 2021 10:12:43 +0800
Subject: [PATCH] Revise MessageSerializers.registerSerializer, fix #951: -
 Don't register contextual serializer - Register polymorphic serializers to
 all superclasses inheriting SingleMessage

---
 .../message/MessageSerializersImpl.kt         | 103 +++++++++++-------
 .../kotlin/message/MessageSerializers.kt      |  21 ++--
 .../kotlin/message/data/MessageChain.kt       |   2 +-
 3 files changed, 79 insertions(+), 47 deletions(-)

diff --git a/mirai-core-api/src/commonMain/kotlin/internal/message/MessageSerializersImpl.kt b/mirai-core-api/src/commonMain/kotlin/internal/message/MessageSerializersImpl.kt
index 224bb06d6..5b0d23178 100644
--- a/mirai-core-api/src/commonMain/kotlin/internal/message/MessageSerializersImpl.kt
+++ b/mirai-core-api/src/commonMain/kotlin/internal/message/MessageSerializersImpl.kt
@@ -22,9 +22,10 @@ import kotlinx.serialization.modules.polymorphic
 import net.mamoe.mirai.Mirai
 import net.mamoe.mirai.message.MessageSerializers
 import net.mamoe.mirai.message.data.*
-import net.mamoe.mirai.message.data.MessageChainImpl
 import net.mamoe.mirai.utils.MiraiInternalApi
 import kotlin.reflect.KClass
+import kotlin.reflect.full.allSuperclasses
+import kotlin.reflect.full.isSubclassOf
 
 
 internal fun ClassSerialDescriptorBuilder.takeElementsFrom(descriptor: SerialDescriptor) {
@@ -70,38 +71,45 @@ public open class MessageSourceSerializerImpl(serialName: String) :
 
 private val builtInSerializersModule by lazy {
     SerializersModule {
-        // non-Message classes
-        contextual(RawForwardMessage::class, RawForwardMessage.serializer())
-        contextual(ForwardMessage.Node::class, ForwardMessage.Node.serializer())
-        contextual(VipFace.Kind::class, VipFace.Kind.serializer())
+        // NOTE: contextual serializers disabled because of https://github.com/mamoe/mirai/issues/951
 
+//        // non-Message classes
+//        contextual(RawForwardMessage::class, RawForwardMessage.serializer())
+//        contextual(ForwardMessage.Node::class, ForwardMessage.Node.serializer())
+//        contextual(VipFace.Kind::class, VipFace.Kind.serializer())
+//
+//
+//        // In case Proguard or something else obfuscated the Kotlin metadata, providing the serializers explicitly will help.
+//        contextual(At::class, At.serializer())
+//        contextual(AtAll::class, AtAll.serializer())
+//        contextual(CustomMessage::class, CustomMessage.serializer())
+//        contextual(CustomMessageMetadata::class, CustomMessageMetadata.serializer())
+//        contextual(Face::class, Face.serializer())
+//        contextual(Image::class, Image.Serializer)
+//        contextual(PlainText::class, PlainText.serializer())
+//        contextual(QuoteReply::class, QuoteReply.serializer())
+//
+//        contextual(ForwardMessage::class, ForwardMessage.serializer())
+//
+//
+//        contextual(LightApp::class, LightApp.serializer())
+//        contextual(SimpleServiceMessage::class, SimpleServiceMessage.serializer())
+//        contextual(AbstractServiceMessage::class, AbstractServiceMessage.serializer())
+//
+//        contextual(PttMessage::class, PttMessage.serializer())
+//        contextual(Voice::class, Voice.serializer())
+//        contextual(PokeMessage::class, PokeMessage.serializer())
+//        contextual(VipFace::class, VipFace.serializer())
+//        contextual(FlashImage::class, FlashImage.serializer())
+//
+//        contextual(MusicShare::class, MusicShare.serializer())
+//
+//        contextual(MessageSource::class, MessageSource.serializer())
 
-        // In case Proguard or something else obfuscated the Kotlin metadata, providing the serializers explicitly will help.
-        contextual(At::class, At.serializer())
-        contextual(AtAll::class, AtAll.serializer())
-        contextual(CustomMessage::class, CustomMessage.serializer())
-        contextual(CustomMessageMetadata::class, CustomMessageMetadata.serializer())
-        contextual(Face::class, Face.serializer())
-        contextual(Image::class, Image.Serializer)
-        contextual(PlainText::class, PlainText.serializer())
-        contextual(QuoteReply::class, QuoteReply.serializer())
+//        contextual(SingleMessage::class, SingleMessage.Serializer)
+        contextual(MessageChain::class, MessageChain.Serializer)
+        contextual(MessageChainImpl::class, MessageChainImpl.serializer())
 
-        contextual(ForwardMessage::class, ForwardMessage.serializer())
-
-
-        contextual(LightApp::class, LightApp.serializer())
-        contextual(SimpleServiceMessage::class, SimpleServiceMessage.serializer())
-        contextual(AbstractServiceMessage::class, AbstractServiceMessage.serializer())
-
-        contextual(PttMessage::class, PttMessage.serializer())
-        contextual(Voice::class, Voice.serializer())
-        contextual(PokeMessage::class, PokeMessage.serializer())
-        contextual(VipFace::class, VipFace.serializer())
-        contextual(FlashImage::class, FlashImage.serializer())
-
-        contextual(MusicShare::class, MusicShare.serializer())
-
-        contextual(MessageSource::class, MessageSource.serializer())
 
         fun PolymorphicModuleBuilder<MessageMetadata>.messageMetadataSubclasses() {
             subclass(MessageSource::class, MessageSource.serializer())
@@ -132,11 +140,6 @@ private val builtInSerializersModule by lazy {
             subclass(MusicShare::class, MusicShare.serializer())
         }
 
-        contextual(SingleMessage::class, SingleMessage.Serializer)
-        contextual(MessageChain::class, MessageChain.Serializer)
-        contextual(MessageChainImpl::class, MessageChainImpl.serializer())
-
-//        polymorphicDefault(MessageChain::class) { MessageChainImpl.serializer() }
 
         //  polymorphic(SingleMessage::class) {
         //      subclass(MessageSource::class, MessageSource.serializer())
@@ -153,6 +156,23 @@ private val builtInSerializersModule by lazy {
             messageMetadataSubclasses()
         }
 
+        polymorphic(MessageContent::class) {
+            messageContentSubclasses()
+        }
+
+        polymorphic(MessageMetadata::class) {
+            messageMetadataSubclasses()
+        }
+
+        polymorphic(RichMessage::class) {
+            subclass(SimpleServiceMessage::class, SimpleServiceMessage.serializer())
+            subclass(LightApp::class, LightApp.serializer())
+        }
+
+        polymorphic(ServiceMessage::class) {
+            subclass(SimpleServiceMessage::class, SimpleServiceMessage.serializer())
+        }
+
         //contextual(SingleMessage::class, SingleMessage.Serializer)
         // polymorphic(SingleMessage::class, SingleMessage.Serializer) {
         //     messageContentSubclasses()
@@ -180,11 +200,16 @@ internal object MessageSerializersImpl : MessageSerializers {
     override val serializersModule: SerializersModule get() = serializersModuleField ?: builtInSerializersModule
 
     @Synchronized
-    override fun <M : SingleMessage> registerSerializer(baseClass: KClass<M>, serializer: KSerializer<M>) {
+    override fun <M : SingleMessage> registerSerializer(type: KClass<M>, serializer: KSerializer<M>) {
         serializersModuleField = serializersModule.overwriteWith(SerializersModule {
-            contextual(baseClass, serializer)
-            polymorphic(SingleMessage::class) {
-                subclass(baseClass, serializer)
+            // contextual(type, serializer)
+            for (superclass in type.allSuperclasses) {
+                if (superclass.isFinal) continue
+                if (!superclass.isSubclassOf(SingleMessage::class)) continue
+                @Suppress("UNCHECKED_CAST")
+                polymorphic(superclass as KClass<Any>) {
+                    subclass(type, serializer)
+                }
             }
         })
     }
diff --git a/mirai-core-api/src/commonMain/kotlin/message/MessageSerializers.kt b/mirai-core-api/src/commonMain/kotlin/message/MessageSerializers.kt
index 2e2b45520..dcaa795cf 100644
--- a/mirai-core-api/src/commonMain/kotlin/message/MessageSerializers.kt
+++ b/mirai-core-api/src/commonMain/kotlin/message/MessageSerializers.kt
@@ -12,7 +12,9 @@ package net.mamoe.mirai.message
 import kotlinx.serialization.ContextualSerializer
 import kotlinx.serialization.KSerializer
 import kotlinx.serialization.json.Json
-import kotlinx.serialization.modules.*
+import kotlinx.serialization.modules.PolymorphicModuleBuilder
+import kotlinx.serialization.modules.SerializersModule
+import kotlinx.serialization.modules.subclass
 import net.mamoe.mirai.internal.message.MessageSerializersImpl
 import net.mamoe.mirai.message.data.Message
 import net.mamoe.mirai.message.data.MessageChain
@@ -50,21 +52,26 @@ public interface MessageSerializers {
     public val serializersModule: SerializersModule
 
     /**
-     * 注册一个 [SerializersModuleBuilder.contextual] 和 [SingleMessage] 多态域的 [PolymorphicModuleBuilder.subclass].
+     * 注册 [serializer] 到 [type] 的所有为 [SingleMessage] 子类型的超类型的多态域 [PolymorphicModuleBuilder.subclass]
      *
-     * 相当于
+     * 实现:
      * ```
-     * contextual(baseClass, serializer)
-     * polymorphic(SingleMessage::class) {
-     *     subclass(baseClass, serializer)
+     * for (superclass in type.allSuperclasses) {
+     *     if (superclass.isFinal) continue
+     *     if (superclass.isSubclassOf(SingleMessage::class)) continue
+     *     polymorphic(superclass) {
+     *         subclass(type, serializer)
+     *     }
      * }
      * ```
      *
      *
      * 若要自己实现消息类型, 务必在这里注册对应序列化器, 否则在 [MessageChain.serializeToJsonString] 时将会出错.
+     *
+     * @since 2.0, revised 2.3
      */
     @MiraiExperimentalApi
-    public fun <M : SingleMessage> registerSerializer(baseClass: KClass<M>, serializer: KSerializer<M>)
+    public fun <M : SingleMessage> registerSerializer(type: KClass<M>, serializer: KSerializer<M>)
 
     /**
      * 合并 [serializersModule] 到 [MessageSerializers.serializersModule] 并覆盖.
diff --git a/mirai-core-api/src/commonMain/kotlin/message/data/MessageChain.kt b/mirai-core-api/src/commonMain/kotlin/message/data/MessageChain.kt
index 9f9cfa63d..f7a6c28b6 100644
--- a/mirai-core-api/src/commonMain/kotlin/message/data/MessageChain.kt
+++ b/mirai-core-api/src/commonMain/kotlin/message/data/MessageChain.kt
@@ -245,7 +245,7 @@ public interface MessageChain :
      */
     public object Serializer : KSerializer<MessageChain> {
         @Suppress("DEPRECATION_ERROR")
-        private val delegate = ListSerializer(PolymorphicSerializer(SingleMessage::class))
+        private val delegate = ListSerializer(SingleMessage.Serializer)
         override val descriptor: SerialDescriptor = delegate.descriptor
         override fun deserialize(decoder: Decoder): MessageChain = delegate.deserialize(decoder).toMessageChain()
         override fun serialize(encoder: Encoder, value: MessageChain): Unit = delegate.serialize(encoder, value)