diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/TypeUtil.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/TypeUtil.kt index 323ca0c433a..81627387ddd 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/TypeUtil.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/TypeUtil.kt @@ -91,6 +91,22 @@ fun AbstractSerialGenerator.getSerialTypeInfo(property: SerializableProperty): S } } +/** + * Returns class descriptor for ContextSerializer or PolymorphicSerializer + * if [annotations] contains @Contextual or @Polymorphic annotation + */ +fun analyzeSpecialSerializers( + moduleDescriptor: ModuleDescriptor, + annotations: Annotations +): ClassDescriptor? = when { + annotations.hasAnnotation(SerializationAnnotations.contextualFqName) -> + moduleDescriptor.getClassFromSerializationPackage(SpecialBuiltins.contextSerializer) + // can be annotation on type usage, e.g. List<@Polymorphic Any> + annotations.hasAnnotation(SerializationAnnotations.polymorphicFqName) -> + moduleDescriptor.getClassFromSerializationPackage(SpecialBuiltins.polymorphicSerializer) + else -> null +} + fun AbstractSerialGenerator.findTypeSerializerOrContext( module: ModuleDescriptor, kType: KotlinType, @@ -100,12 +116,8 @@ fun AbstractSerialGenerator.findTypeSerializerOrContext( if (kType.isTypeParameter()) return null if (kType.isMarkedNullable) return findTypeSerializerOrContext(module, kType.makeNotNullable(), annotations, sourceElement) additionalSerializersInScopeOfCurrentFile[kType]?.let { return it } - fun getContextualSerializer() = - if (annotations.hasAnnotation(SerializationAnnotations.contextualFqName) || kType in contextualKClassListInCurrentFile) - module.getClassFromSerializationPackage(SpecialBuiltins.contextSerializer) - else - null - return getContextualSerializer() ?: findTypeSerializer(module, kType) ?: throw CompilationException( + if (kType in contextualKClassListInCurrentFile) return module.getClassFromSerializationPackage(SpecialBuiltins.contextSerializer) + return analyzeSpecialSerializers(module, annotations) ?: findTypeSerializer(module, kType) ?: throw CompilationException( "Serializer for element of type $kType has not been found.\n" + "To use context serializer as fallback, explicitly annotate element with @ContextualSerialization", null, @@ -116,7 +128,6 @@ fun AbstractSerialGenerator.findTypeSerializerOrContext( fun findTypeSerializer(module: ModuleDescriptor, kType: KotlinType): ClassDescriptor? { val userOverride = kType.overridenSerializer if (userOverride != null) return userOverride.toClassDescriptor - if (kType.requiresPolymorphism()) return findPolymorphicSerializer(module) if (kType.isTypeParameter()) return null if (KotlinBuiltIns.isArray(kType)) return module.getClassFromInternalSerializationPackage(SpecialBuiltins.referenceArraySerializer) return kType.typeSerializer.toClassDescriptor // check for serializer defined on the type @@ -170,16 +181,6 @@ fun findEnumTypeSerializer(module: ModuleDescriptor, kType: KotlinType): ClassDe return if (classDescriptor.kind == ClassKind.ENUM_CLASS) module.findClassAcrossModuleDependencies(enumSerializerId) else null } -fun KotlinType.requiresPolymorphism(): Boolean { - return this.toClassDescriptor?.getSuperClassNotAny()?.isInternalSerializable == true - || (this.toClassDescriptor?.modality != Modality.FINAL && this.toClassDescriptor?.unsubstitutedPrimaryConstructor != null) // open not java class - || this.containsTypeProjectionsInTopLevelArguments() // List<*> -} - -fun findPolymorphicSerializer(module: ModuleDescriptor): ClassDescriptor { - return requireNotNull(module.findClassAcrossModuleDependencies(polymorphicSerializerId)) { "Can't locate polymorphic serializer definition" } -} - fun KtPureClassOrObject.bodyPropertiesDescriptorsMap(bindingContext: BindingContext): Map = declarations .asSequence() .filterIsInstance() diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/NamingConventions.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/NamingConventions.kt index 7f83fb63cd9..822a44f1dc7 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/NamingConventions.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/NamingConventions.kt @@ -22,6 +22,7 @@ object SerializationAnnotations { internal val serialInfoFqName = FqName("kotlinx.serialization.SerialInfo") internal val contextualFqName = FqName("kotlinx.serialization.ContextualSerialization") + internal val polymorphicFqName = FqName("kotlinx.serialization.Polymorphic") internal val additionalSerializersFqName = FqName("kotlinx.serialization.UseSerializers") } diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/SerializableProperty.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/SerializableProperty.kt index b20eddeeaf4..a959da01d81 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/SerializableProperty.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/SerializableProperty.kt @@ -19,13 +19,12 @@ package org.jetbrains.kotlinx.serialization.compiler.resolve import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor -import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.psi.KtDeclarationWithInitializer import org.jetbrains.kotlin.psi.KtParameter import org.jetbrains.kotlin.psi.ValueArgument import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.source.getPsi -import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlinx.serialization.compiler.backend.common.analyzeSpecialSerializers class SerializableProperty( val descriptor: PropertyDescriptor, @@ -36,18 +35,11 @@ class SerializableProperty( val type = descriptor.type val genericIndex = type.genericIndex val module = descriptor.module - val serializableWith = extractSerializableWith(descriptor.annotations) + val serializableWith = descriptor.serializableWith ?: analyzeSpecialSerializers(module, descriptor.annotations)?.defaultType val optional = !descriptor.annotations.serialRequired && descriptor.declaresDefaultValue val transient = descriptor.annotations.serialTransient || !hasBackingField val annotationsWithArguments: List, List>> = descriptor.annotationsWithArguments() - - private fun extractSerializableWith(annotations: Annotations): KotlinType? { - descriptor.serializableWith?.let { return it } - return if (annotations.hasAnnotation(SerializationAnnotations.contextualFqName)) - module.getClassFromSerializationPackage(SpecialBuiltins.contextSerializer).defaultType - else null - } } val PropertyDescriptor.declaresDefaultValue: Boolean