diff --git a/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/ClassDeserialization.kt b/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/ClassDeserialization.kt index 6bd789d08cf..0cc4ead43ab 100644 --- a/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/ClassDeserialization.kt +++ b/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/ClassDeserialization.kt @@ -32,6 +32,7 @@ import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl import org.jetbrains.kotlin.fir.types.toLookupTag import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinarySourceElement import org.jetbrains.kotlin.metadata.ProtoBuf +import org.jetbrains.kotlin.metadata.SerializationPluginMetadataExtensions import org.jetbrains.kotlin.metadata.deserialization.* import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf import org.jetbrains.kotlin.name.* @@ -139,7 +140,7 @@ fun deserializeClassToSymbol( ) addDeclarations( - classProto.propertyList.map { + classProto.propertiesInOrder(context).map { classDeserializer.loadProperty(it, classProto, symbol) } ) @@ -314,10 +315,23 @@ abstract class DeserializedClassConfigurator(val session: FirSession) : FirSessi open fun FirRegularClass.configure(classId: ClassId) {} } -class JvmDeserializedClassConfigurator(session: FirSession): DeserializedClassConfigurator(session) { +class JvmDeserializedClassConfigurator(session: FirSession) : DeserializedClassConfigurator(session) { override fun FirRegularClassBuilder.configure(classId: ClassId) { addSerializableIfNeeded(classId) } } +private fun ProtoBuf.ClassOrBuilder.propertiesInOrder(context: FirDeserializationContext): List { + val properties = propertyList + val versionRequirements = VersionRequirement.create(this, context.nameResolver, context.versionRequirementTable) + if (versionRequirements.any { it.version.major >= 2 }) return properties + val order = getExtension(SerializationPluginMetadataExtensions.propertiesNamesInProgramOrder) + .takeIf { it.isNotEmpty() } + ?: return properties + val propertiesByName = properties.groupBy { it.name } + return order.flatMap { propertiesByName[it] ?: emptyList() }.also { + assert(it.size == properties.size) + } +} + val FirSession.deserializedClassConfigurator: DeserializedClassConfigurator? by FirSession.nullableSessionComponentAccessor() diff --git a/plugins/kotlinx-serialization/kotlinx-serialization.k1/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationPluginMetadataExtensions.java b/core/metadata/src/org/jetbrains/kotlin/metadata/SerializationPluginMetadataExtensions.java similarity index 78% rename from plugins/kotlinx-serialization/kotlinx-serialization.k1/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationPluginMetadataExtensions.java rename to core/metadata/src/org/jetbrains/kotlin/metadata/SerializationPluginMetadataExtensions.java index 6a1b35d0d69..185b0b38fd0 100644 --- a/plugins/kotlinx-serialization/kotlinx-serialization.k1/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationPluginMetadataExtensions.java +++ b/core/metadata/src/org/jetbrains/kotlin/metadata/SerializationPluginMetadataExtensions.java @@ -1,13 +1,13 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! -// source: plugins/kotlinx-serialization/kotlinx-serialization.k1/src/class_extensions.proto +// source: core/metadata/src/properties_order_extension.proto -package org.jetbrains.kotlinx.serialization.compiler.extensions; +package org.jetbrains.kotlin.metadata; public final class SerializationPluginMetadataExtensions { private SerializationPluginMetadataExtensions() {} public static void registerAllExtensions( org.jetbrains.kotlin.protobuf.ExtensionRegistryLite registry) { - registry.add(org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginMetadataExtensions.propertiesNamesInProgramOrder); + registry.add(org.jetbrains.kotlin.metadata.SerializationPluginMetadataExtensions.propertiesNamesInProgramOrder); } public static final int PROPERTIES_NAMES_IN_PROGRAM_ORDER_FIELD_NUMBER = 18000; /** diff --git a/core/metadata/src/org/jetbrains/kotlin/metadata/deserialization/VersionRequirement.kt b/core/metadata/src/org/jetbrains/kotlin/metadata/deserialization/VersionRequirement.kt index ead0082717e..eae402e9330 100644 --- a/core/metadata/src/org/jetbrains/kotlin/metadata/deserialization/VersionRequirement.kt +++ b/core/metadata/src/org/jetbrains/kotlin/metadata/deserialization/VersionRequirement.kt @@ -6,7 +6,7 @@ package org.jetbrains.kotlin.metadata.deserialization import org.jetbrains.kotlin.metadata.ProtoBuf -import org.jetbrains.kotlin.protobuf.MessageLite +import org.jetbrains.kotlin.protobuf.MessageLiteOrBuilder class VersionRequirementTable private constructor(private val infos: List) { operator fun get(id: Int): ProtoBuf.VersionRequirement? = infos.getOrNull(id) @@ -81,7 +81,7 @@ class VersionRequirement( "since $version $level" + (if (errorCode != null) " error $errorCode" else "") + (if (message != null) ": $message" else "") companion object { - fun create(proto: MessageLite, nameResolver: NameResolver, table: VersionRequirementTable): List { + fun create(proto: MessageLiteOrBuilder, nameResolver: NameResolver, table: VersionRequirementTable): List { val ids = when (proto) { is ProtoBuf.Class -> proto.versionRequirementList is ProtoBuf.Constructor -> proto.versionRequirementList diff --git a/plugins/kotlinx-serialization/kotlinx-serialization.k1/src/class_extensions.proto b/core/metadata/src/properties_order_extension.proto similarity index 82% rename from plugins/kotlinx-serialization/kotlinx-serialization.k1/src/class_extensions.proto rename to core/metadata/src/properties_order_extension.proto index 85243eb4d76..89223b83973 100644 --- a/plugins/kotlinx-serialization/kotlinx-serialization.k1/src/class_extensions.proto +++ b/core/metadata/src/properties_order_extension.proto @@ -1,4 +1,4 @@ -package org.jetbrains.kotlinx.serialization.compiler.extensions; +package org.jetbrains.kotlin.metadata; import "core/metadata/src/metadata.proto"; import "core/metadata/src/ext_options.proto"; diff --git a/generators/protobuf/GenerateProtoBuf.kt b/generators/protobuf/GenerateProtoBuf.kt index e9372c93348..91004645c83 100644 --- a/generators/protobuf/GenerateProtoBuf.kt +++ b/generators/protobuf/GenerateProtoBuf.kt @@ -46,6 +46,7 @@ class ProtoPath(val file: String, val generateDebug: Boolean = true) { val PROTO_PATHS: List = listOf( ProtoPath("core/metadata/src/metadata.proto"), ProtoPath("core/metadata/src/builtins.proto"), + ProtoPath("core/metadata/src/properties_order_extension.proto", generateDebug = false), ProtoPath("js/js.serializer/src/js.proto"), ProtoPath("js/js.serializer/src/js-ast.proto", false), ProtoPath("core/metadata.jvm/src/jvm_metadata.proto"), @@ -54,7 +55,6 @@ val PROTO_PATHS: List = listOf( ProtoPath("compiler/util-klib-metadata/src/KlibMetadataProtoBuf.proto"), ProtoPath("compiler/ir/serialization.common/src/KotlinIr.proto", false), ProtoPath("compiler/ir/serialization.jvm/src/JvmIr.proto", false), - ProtoPath("plugins/kotlinx-serialization/kotlinx-serialization.k1/src/class_extensions.proto", generateDebug = false) ) private val EXT_OPTIONS_PROTO_PATH = ProtoPath("core/metadata/src/ext_options.proto") diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KotlinxSerializationMppK2IT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/K2KotlinxSerializationIT.kt similarity index 69% rename from libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KotlinxSerializationMppK2IT.kt rename to libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/K2KotlinxSerializationIT.kt index 2668cabdb94..fef6aa624b8 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KotlinxSerializationMppK2IT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/K2KotlinxSerializationIT.kt @@ -10,7 +10,7 @@ import org.jetbrains.kotlin.gradle.testbase.* import org.junit.jupiter.api.DisplayName @OtherGradlePluginTests -class KotlinxSerializationMppK2IT : KGPBaseTest() { +class K2KotlinxSerializationIT : KGPBaseTest() { private val gradleVersion = GradleVersion.version(TestVersions.Gradle.MAX_SUPPORTED) @DisplayName("Compile common code to metadata with kotlinx.serialization and K2") @@ -19,7 +19,16 @@ class KotlinxSerializationMppK2IT : KGPBaseTest() { project("kotlinxSerializationMppK2", gradleVersion) { build(":compileCommonMainKotlinMetadata") { assertTasksExecuted(":compileCommonMainKotlinMetadata") - assertOutputContains("BUILD SUCCESSFUL") + } + } + } + + @DisplayName("Compile code with kotlinx.serialization with K2 against K1") + @GradleTest + fun `test kotlinx serialization K2 against K1`() { + project("kotlinxSerializationK2AgainstK1", gradleVersion) { + build(":app:run") { + assertTasksExecuted(":app:run") } } } diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlinxSerializationK2AgainstK1/app/build.gradle.kts b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlinxSerializationK2AgainstK1/app/build.gradle.kts new file mode 100644 index 00000000000..ad18e2ea994 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlinxSerializationK2AgainstK1/app/build.gradle.kts @@ -0,0 +1,20 @@ +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile +import org.jetbrains.kotlin.gradle.dsl.KotlinVersion + +plugins { + application +} + +dependencies { + implementation(project(":lib")) +} + +val compileKotlin: KotlinCompile by tasks + +compileKotlin.compilerOptions { + languageVersion.set(KotlinVersion.KOTLIN_2_0) +} + +application { + mainClass.set("foo.MainKt") +} diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlinxSerializationK2AgainstK1/app/src/main/kotlin/Main.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlinxSerializationK2AgainstK1/app/src/main/kotlin/Main.kt new file mode 100644 index 00000000000..9f654f55359 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlinxSerializationK2AgainstK1/app/src/main/kotlin/Main.kt @@ -0,0 +1,32 @@ +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ +package foo + +import kotlinx.serialization.json.Json +import kotlinx.serialization.Serializable + +@Serializable +class Derived(val d: Long = 1000000000000) : Base(2, "world", listOf("b", "c")) { + override fun equals(other: Any?): Boolean { + if (other !is Derived) return false + return a == other.a && b == other.b && c == other.c && d == other.d + } + + override fun toString(): String { + return "a: $a, b: $b, c: $c, d: $d" + } +} + +fun main() { + val expected = Derived(12) + val result = Json.encodeToString(Derived.serializer(), expected) + if (result != """{"c":2,"b":"world","a":["b","c"],"d":12}""") { + throw IllegalStateException("Error: $result") + } + val actual = Json.decodeFromString(Derived.serializer(), result) + if (expected != actual) { + throw IllegalStateException("expected: $expected\nactual: $actual") + } +} diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlinxSerializationK2AgainstK1/build.gradle.kts b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlinxSerializationK2AgainstK1/build.gradle.kts new file mode 100644 index 00000000000..1ede667184e --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlinxSerializationK2AgainstK1/build.gradle.kts @@ -0,0 +1,27 @@ +plugins { + kotlin("jvm") apply false + kotlin("plugin.serialization") apply false + java +} + +repositories { + mavenLocal() + mavenCentral() +} + +subprojects { + apply { + plugin("java") + plugin("kotlin") + plugin("org.jetbrains.kotlin.plugin.serialization") + } + + repositories { + mavenLocal() + mavenCentral() + } + + dependencies { + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0") + } +} diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlinxSerializationK2AgainstK1/lib/build.gradle.kts b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlinxSerializationK2AgainstK1/lib/build.gradle.kts new file mode 100644 index 00000000000..6e872c1ee72 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlinxSerializationK2AgainstK1/lib/build.gradle.kts @@ -0,0 +1,8 @@ +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile +import org.jetbrains.kotlin.gradle.dsl.KotlinVersion + +val compileKotlin: KotlinCompile by tasks + +compileKotlin.compilerOptions { + languageVersion.set(KotlinVersion.KOTLIN_1_9) +} diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlinxSerializationK2AgainstK1/lib/src/main/kotlin/Base.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlinxSerializationK2AgainstK1/lib/src/main/kotlin/Base.kt new file mode 100644 index 00000000000..60cf1324e55 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlinxSerializationK2AgainstK1/lib/src/main/kotlin/Base.kt @@ -0,0 +1,14 @@ +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ +package foo + +import kotlinx.serialization.Serializable + +@Serializable +open class Base( + val c: Int = 1, + val b: String = "hello", + val a: List = listOf("a") +) diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlinxSerializationK2AgainstK1/settings.gradle.kts b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlinxSerializationK2AgainstK1/settings.gradle.kts new file mode 100644 index 00000000000..4a3efb244b0 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlinxSerializationK2AgainstK1/settings.gradle.kts @@ -0,0 +1,3 @@ +rootProject.name = "kotlinxSerializationK2AgainstK1" + +include(":lib", "app") diff --git a/plugins/kotlinx-serialization/kotlinx-serialization.cli/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationComponentRegistrar.kt b/plugins/kotlinx-serialization/kotlinx-serialization.cli/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationComponentRegistrar.kt index 2bf47b2c74d..0d57499f35a 100644 --- a/plugins/kotlinx-serialization/kotlinx-serialization.cli/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationComponentRegistrar.kt +++ b/plugins/kotlinx-serialization/kotlinx-serialization.cli/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationComponentRegistrar.kt @@ -17,6 +17,7 @@ import org.jetbrains.kotlin.extensions.StorageComponentContainerContributor import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrarAdapter import org.jetbrains.kotlin.js.translate.extensions.JsSyntheticTranslateExtension import org.jetbrains.kotlin.library.metadata.KlibMetadataSerializerProtocol +import org.jetbrains.kotlin.metadata.SerializationPluginMetadataExtensions import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil import org.jetbrains.kotlin.platform.TargetPlatform import org.jetbrains.kotlin.resolve.extensions.SyntheticResolveExtension diff --git a/plugins/kotlinx-serialization/kotlinx-serialization.k1/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationDescriptorSerializerPlugin.kt b/plugins/kotlinx-serialization/kotlinx-serialization.k1/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationDescriptorSerializerPlugin.kt index df604d678f0..7094d1ab144 100644 --- a/plugins/kotlinx-serialization/kotlinx-serialization.k1/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationDescriptorSerializerPlugin.kt +++ b/plugins/kotlinx-serialization/kotlinx-serialization.k1/src/org/jetbrains/kotlinx/serialization/compiler/extensions/SerializationDescriptorSerializerPlugin.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlinx.serialization.compiler.extensions import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.metadata.ProtoBuf +import org.jetbrains.kotlin.metadata.SerializationPluginMetadataExtensions import org.jetbrains.kotlin.metadata.serialization.MutableVersionRequirementTable import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.serialization.DescriptorSerializer @@ -45,4 +46,4 @@ class SerializationDescriptorSerializerPlugin : DescriptorSerializerPlugin { ) descriptorMetadataMap.remove(descriptor) } -} \ No newline at end of file +} diff --git a/plugins/kotlinx-serialization/kotlinx-serialization.k1/src/org/jetbrains/kotlinx/serialization/compiler/resolve/SerializableProperties.kt b/plugins/kotlinx-serialization/kotlinx-serialization.k1/src/org/jetbrains/kotlinx/serialization/compiler/resolve/SerializableProperties.kt index f7125a57381..6ddf67760d1 100644 --- a/plugins/kotlinx-serialization/kotlinx-serialization.k1/src/org/jetbrains/kotlinx/serialization/compiler/resolve/SerializableProperties.kt +++ b/plugins/kotlinx-serialization/kotlinx-serialization.k1/src/org/jetbrains/kotlinx/serialization/compiler/resolve/SerializableProperties.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlinx.serialization.compiler.resolve import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.metadata.SerializationPluginMetadataExtensions import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.KtDeclarationWithInitializer import org.jetbrains.kotlin.psi.KtParameter @@ -19,7 +20,6 @@ import org.jetbrains.kotlin.serialization.deserialization.descriptors.Deserializ import org.jetbrains.kotlin.serialization.deserialization.getName import org.jetbrains.kotlinx.serialization.compiler.diagnostic.SERIALIZABLE_PROPERTIES import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationDescriptorSerializerPlugin -import org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginMetadataExtensions class SerializableProperties(private val serializableClass: ClassDescriptor, val bindingContext: BindingContext) : ISerializableProperties {