Prioritize @Serializable annotation on type usage over class usage
In `val p: @Serializable(X) Foo` and `@Serializable(Y) class Foo` situation, now X would be chosen as serializer. Fixes https://github.com/Kotlin/kotlinx.serialization/issues/1895
This commit is contained in:
committed by
Space Team
parent
d2d13c8765
commit
242b83edbd
+4
-3
@@ -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
|
||||
|
||||
+1
-1
@@ -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,
|
||||
|
||||
+2
-2
@@ -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)
|
||||
|
||||
+7
-7
@@ -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
|
||||
|
||||
@@ -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<Bruh> {
|
||||
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<Bruh> {
|
||||
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"
|
||||
}
|
||||
+6
@@ -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 {
|
||||
|
||||
+6
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user