From 51be4e7f056867469a4966e1fe63f0bcdc78ba6e Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Sun, 9 Jan 2022 10:25:24 +0100 Subject: [PATCH] =?UTF-8?q?don't=20use=20official=20`::kotlin.get().serial?= =?UTF-8?q?izer()`=20API=20=E2=80=94=20avoid=20kotlin=20refection=20wrappe?= =?UTF-8?q?r=20creation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/Kotlin/kotlinx.serialization/issues/1819 GitOrigin-RevId: 9a1bce7a70b6c68c9c6267baa53ac0509b9ff294 --- .../src/xml/KotlinxSerializationBinding.kt | 19 ++++++++++++++++++- .../src/xml/xmlSerializer.kt | 6 +----- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/platform/object-serializer/src/xml/KotlinxSerializationBinding.kt b/platform/object-serializer/src/xml/KotlinxSerializationBinding.kt index 0ae0856e43fce..d810f5e49e182 100644 --- a/platform/object-serializer/src/xml/KotlinxSerializationBinding.kt +++ b/platform/object-serializer/src/xml/KotlinxSerializationBinding.kt @@ -9,6 +9,8 @@ import kotlinx.serialization.KSerializer import kotlinx.serialization.json.Json import org.jdom.CDATA import org.jdom.Element +import java.lang.invoke.MethodHandles +import java.lang.invoke.MethodType @OptIn(ExperimentalSerializationApi::class) private val json = Json { @@ -17,7 +19,22 @@ private val json = Json { ignoreUnknownKeys = true } -internal class KotlinxSerializationBinding(private val serializer: KSerializer) : NotNullDeserializeBinding() { +private val lookup = MethodHandles.lookup() +private val kotlinMethodType = MethodType.methodType(KSerializer::class.java) + +internal class KotlinxSerializationBinding(aClass: Class<*>) : NotNullDeserializeBinding() { + private val serializer: KSerializer + + init { + // don't use official `::kotlin.get().serializer()` API — avoid kotlin refection wrapper creation + // findStaticGetter cannot be used because type of Companion not used + val field = aClass.getDeclaredField("Companion") + field.isAccessible = true + val companion = lookup.unreflectGetter(field).invoke() + @Suppress("UNCHECKED_CAST") + serializer = lookup.findVirtual(companion.javaClass, "serializer", kotlinMethodType).invoke(companion) as KSerializer + } + override fun serialize(o: Any, context: Any?, filter: SerializationFilter?): Any { val element = Element("state") element.addContent(CDATA(json.encodeToString(serializer, o))) diff --git a/platform/object-serializer/src/xml/xmlSerializer.kt b/platform/object-serializer/src/xml/xmlSerializer.kt index 6852c8edcfc1f..fa7e99641db7b 100644 --- a/platform/object-serializer/src/xml/xmlSerializer.kt +++ b/platform/object-serializer/src/xml/xmlSerializer.kt @@ -10,9 +10,7 @@ import com.intellij.serialization.xml.KotlinAwareBeanBinding import com.intellij.serialization.xml.KotlinxSerializationBinding import com.intellij.util.io.URLUtil import com.intellij.util.xmlb.* -import kotlinx.serialization.InternalSerializationApi import kotlinx.serialization.Serializable -import kotlinx.serialization.serializer import org.jdom.Element import org.jdom.JDOMException import org.jetbrains.annotations.TestOnly @@ -172,14 +170,12 @@ private abstract class OldBindingProducer { } private class MyXmlSerializer : XmlSerializerImpl.XmlSerializerBase() { - @OptIn(InternalSerializationApi::class) val bindingProducer = object : OldBindingProducer() { override fun createRootBinding(aClass: Class<*>, type: Type, cacheKey: Type, map: MutableMap): Binding { var binding = createClassBinding(aClass, null, type) if (binding == null) { if (aClass.isAnnotationPresent(Serializable::class.java)) { - @Suppress("UNCHECKED_CAST") - binding = KotlinxSerializationBinding((aClass as Class)::kotlin.get().serializer()) + binding = KotlinxSerializationBinding(aClass) } else { binding = KotlinAwareBeanBinding(aClass)