diff --git a/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializerSearchUtil.kt b/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializerSearchUtil.kt index ea0012dc3d8..448df314301 100644 --- a/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializerSearchUtil.kt +++ b/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializerSearchUtil.kt @@ -46,7 +46,7 @@ fun BaseIrGenerator.getIrSerialTypeInfo(property: IrSerializableProperty, ctx: S val T = property.type property.serializableWith(ctx)?.let { return SerializableInfo(it) } findAddOnSerializer(T, ctx)?.let { return SerializableInfo(it) } - T.overridenSerializer?.let { return SerializableInfo(it) } + T.overriddenSerializer?.let { return SerializableInfo(it) } return when { T.isTypeParameter() -> IrSerialTypeInfo(property, if (property.type.isMarkedNullable()) "Nullable" else "", null) T.isPrimitiveType() -> IrSerialTypeInfo( @@ -112,7 +112,7 @@ fun analyzeSpecialSerializers( fun findTypeSerializer(context: SerializationBaseContext, type: IrType): IrClassSymbol? { - type.overridenSerializer?.let { return it } + type.overriddenSerializer?.let { return it } if (type.isTypeParameter()) return null if (type.isArray()) return context.referenceClassId(referenceArraySerializerId) if (type.isGeneratedSerializableObject()) return context.referenceClassId(objectSerializerId) @@ -166,8 +166,9 @@ internal fun IrClass.polymorphicSerializerIfApplicableAutomatically(context: Ser } } -internal val IrType.overridenSerializer: IrClassSymbol? +internal val IrType.overriddenSerializer: IrClassSymbol? get() { + annotations.serializableWith()?.let { return it } val desc = this.classOrNull ?: return null desc.owner.serializableWith?.let { return it } return null diff --git a/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/JVMCodegenUtil.kt b/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/JVMCodegenUtil.kt index da8ccedb683..b1fc6beefbf 100644 --- a/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/JVMCodegenUtil.kt +++ b/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/JVMCodegenUtil.kt @@ -538,7 +538,7 @@ fun AbstractSerialGenerator.getSerialTypeInfo(property: SerializableProperty, ty property.serializableWith?.toClassDescriptor?.let { return SerializableInfo(it) } findAddOnSerializer(property.type, property.module)?.let { return SerializableInfo(it) } - property.type.overridenSerializer?.toClassDescriptor?.let { return SerializableInfo(it) } + property.type.overriddenSerializer(property.module)?.toClassDescriptor?.let { return SerializableInfo(it) } if (property.type.isTypeParameter()) return JVMSerialTypeInfo( property, diff --git a/plugins/kotlinx-serialization/kotlinx-serialization.k1/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/TypeUtil.kt b/plugins/kotlinx-serialization/kotlinx-serialization.k1/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/TypeUtil.kt index adb26e2b55d..b0279d396a2 100644 --- a/plugins/kotlinx-serialization/kotlinx-serialization.k1/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/TypeUtil.kt +++ b/plugins/kotlinx-serialization/kotlinx-serialization.k1/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/TypeUtil.kt @@ -54,7 +54,7 @@ fun AbstractSerialGenerator.getSerialTypeInfo(property: SerializableProperty): S val T = property.type property.serializableWith?.toClassDescriptor?.let { return SerializableInfo(it) } findAddOnSerializer(T, property.module)?.let { return SerializableInfo(it) } - T.overridenSerializer?.toClassDescriptor?.let { return SerializableInfo(it) } + T.overriddenSerializer(property.module)?.toClassDescriptor?.let { return SerializableInfo(it) } return when { T.isTypeParameter() -> SerialTypeInfo(property, if (property.type.isMarkedNullable) "Nullable" else "", null) T.isPrimitiveNumberType() or T.isBoolean() -> SerialTypeInfo( @@ -147,7 +147,7 @@ fun AbstractSerialGenerator?.findTypeSerializerOrContext( } fun findTypeSerializer(module: ModuleDescriptor, kType: KotlinType): ClassDescriptor? { - val userOverride = kType.overridenSerializer + val userOverride = kType.overriddenSerializer(module) if (userOverride != null) return userOverride.toClassDescriptor if (kType.isTypeParameter()) return null if (KotlinBuiltIns.isArray(kType)) return module.getClassFromInternalSerializationPackage(SpecialBuiltins.referenceArraySerializer) diff --git a/plugins/kotlinx-serialization/kotlinx-serialization.k1/src/org/jetbrains/kotlinx/serialization/compiler/resolve/KSerializationUtil.kt b/plugins/kotlinx-serialization/kotlinx-serialization.k1/src/org/jetbrains/kotlinx/serialization/compiler/resolve/KSerializationUtil.kt index b020cb8ed92..e645c0339f8 100644 --- a/plugins/kotlinx-serialization/kotlinx-serialization.k1/src/org/jetbrains/kotlinx/serialization/compiler/resolve/KSerializationUtil.kt +++ b/plugins/kotlinx-serialization/kotlinx-serialization.k1/src/org/jetbrains/kotlinx/serialization/compiler/resolve/KSerializationUtil.kt @@ -245,13 +245,13 @@ val ClassDescriptor?.classSerializer: ClassDescriptor? val ClassDescriptor.hasCompanionObjectAsSerializer: Boolean get() = isInternallySerializableObject || companionObjectDescriptor?.serializerForClass == this.defaultType -// returns only user-overriden Serializer -val KotlinType.overridenSerializer: KotlinType? - get() { - val desc = this.toClassDescriptor ?: return null - desc.serializableWith?.let { return it } - return null - } +// returns only user-overridden Serializer +fun KotlinType.overriddenSerializer(module: ModuleDescriptor): KotlinType? { + annotations.serializableWith(module)?.let { return it } + val desc = this.toClassDescriptor ?: return null + desc.serializableWith?.let { return it } + return null +} val KotlinType.genericIndex: Int? get() = (this.constructor.declarationDescriptor as? TypeParameterDescriptor)?.index diff --git a/plugins/kotlinx-serialization/testData/boxIr/serializableOnPropertyType.kt b/plugins/kotlinx-serialization/testData/boxIr/serializableOnPropertyType.kt new file mode 100644 index 00000000000..2eaa571f174 --- /dev/null +++ b/plugins/kotlinx-serialization/testData/boxIr/serializableOnPropertyType.kt @@ -0,0 +1,56 @@ +// TARGET_BACKEND: JVM_IR + +// WITH_STDLIB + +import kotlinx.serialization.* +import kotlinx.serialization.json.* +import kotlinx.serialization.descriptors.* +import kotlinx.serialization.encoding.* +import kotlinx.serialization.internal.* + + +@Serializable(BruhSerializerA::class) +class Bruh(val s: String) + +object BruhSerializerA : KSerializer { + override val descriptor: SerialDescriptor + get() = PrimitiveSerialDescriptor("Bruh", PrimitiveKind.STRING) + + override fun serialize(encoder: Encoder, value: Bruh) { + encoder.encodeString(value.s) + } + + override fun deserialize(decoder: Decoder): Bruh { + return Bruh(decoder.decodeString()) + } +} + +object BruhSerializerB : KSerializer { + override val descriptor: SerialDescriptor + get() = PrimitiveSerialDescriptor("Bruh", PrimitiveKind.STRING) + + override fun serialize(encoder: Encoder, value: Bruh) { + encoder.encodeString(value.s + "#") + } + + override fun deserialize(decoder: Decoder): Bruh { + return Bruh(decoder.decodeString().removeSuffix("#")) + } +} + +typealias BruhAlias = @Serializable(BruhSerializerB::class) Bruh + +@Serializable +class Tester( + val b1: Bruh, + @Serializable(BruhSerializerB::class) val b2: Bruh, + val b3: @Serializable(BruhSerializerB::class) Bruh, + val b4: BruhAlias +) + +fun box(): String { + val t = Tester(Bruh("a"), Bruh("b"), Bruh("c"), Bruh("d")) + val s = Json.encodeToString(t) + if (s != """{"b1":"a","b2":"b#","b3":"c#","b4":"d#"}""") return s + return "OK" +} \ No newline at end of file diff --git a/plugins/kotlinx-serialization/tests-gen/org/jetbrains/kotlinx/serialization/runners/SerializationFirBlackBoxTestGenerated.java b/plugins/kotlinx-serialization/tests-gen/org/jetbrains/kotlinx/serialization/runners/SerializationFirBlackBoxTestGenerated.java index ddf73f2adb0..c12c1f1d0b9 100644 --- a/plugins/kotlinx-serialization/tests-gen/org/jetbrains/kotlinx/serialization/runners/SerializationFirBlackBoxTestGenerated.java +++ b/plugins/kotlinx-serialization/tests-gen/org/jetbrains/kotlinx/serialization/runners/SerializationFirBlackBoxTestGenerated.java @@ -105,6 +105,12 @@ public class SerializationFirBlackBoxTestGenerated extends AbstractSerialization runTest("plugins/kotlinx-serialization/testData/boxIr/sealedInterfaces.kt"); } + @Test + @TestMetadata("serializableOnPropertyType.kt") + public void testSerializableOnPropertyType() throws Exception { + runTest("plugins/kotlinx-serialization/testData/boxIr/serializableOnPropertyType.kt"); + } + @Test @TestMetadata("starProjections.kt") public void testStarProjections() throws Exception { diff --git a/plugins/kotlinx-serialization/tests-gen/org/jetbrains/kotlinx/serialization/runners/SerializationIrBoxTestGenerated.java b/plugins/kotlinx-serialization/tests-gen/org/jetbrains/kotlinx/serialization/runners/SerializationIrBoxTestGenerated.java index 4133f186860..fec91fabe89 100644 --- a/plugins/kotlinx-serialization/tests-gen/org/jetbrains/kotlinx/serialization/runners/SerializationIrBoxTestGenerated.java +++ b/plugins/kotlinx-serialization/tests-gen/org/jetbrains/kotlinx/serialization/runners/SerializationIrBoxTestGenerated.java @@ -103,6 +103,12 @@ public class SerializationIrBoxTestGenerated extends AbstractSerializationIrBoxT runTest("plugins/kotlinx-serialization/testData/boxIr/sealedInterfaces.kt"); } + @Test + @TestMetadata("serializableOnPropertyType.kt") + public void testSerializableOnPropertyType() throws Exception { + runTest("plugins/kotlinx-serialization/testData/boxIr/serializableOnPropertyType.kt"); + } + @Test @TestMetadata("starProjections.kt") public void testStarProjections() throws Exception {