Do not enable PolymorphicSerializer without special annotation

This commit is contained in:
Leonid Startsev
2018-11-23 17:52:18 +03:00
parent 9d707cb1d9
commit 859c95c3c4
3 changed files with 21 additions and 27 deletions
@@ -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( fun AbstractSerialGenerator.findTypeSerializerOrContext(
module: ModuleDescriptor, module: ModuleDescriptor,
kType: KotlinType, kType: KotlinType,
@@ -100,12 +116,8 @@ fun AbstractSerialGenerator.findTypeSerializerOrContext(
if (kType.isTypeParameter()) return null if (kType.isTypeParameter()) return null
if (kType.isMarkedNullable) return findTypeSerializerOrContext(module, kType.makeNotNullable(), annotations, sourceElement) if (kType.isMarkedNullable) return findTypeSerializerOrContext(module, kType.makeNotNullable(), annotations, sourceElement)
additionalSerializersInScopeOfCurrentFile[kType]?.let { return it } additionalSerializersInScopeOfCurrentFile[kType]?.let { return it }
fun getContextualSerializer() = if (kType in contextualKClassListInCurrentFile) return module.getClassFromSerializationPackage(SpecialBuiltins.contextSerializer)
if (annotations.hasAnnotation(SerializationAnnotations.contextualFqName) || kType in contextualKClassListInCurrentFile) return analyzeSpecialSerializers(module, annotations) ?: findTypeSerializer(module, kType) ?: throw CompilationException(
module.getClassFromSerializationPackage(SpecialBuiltins.contextSerializer)
else
null
return getContextualSerializer() ?: findTypeSerializer(module, kType) ?: throw CompilationException(
"Serializer for element of type $kType has not been found.\n" + "Serializer for element of type $kType has not been found.\n" +
"To use context serializer as fallback, explicitly annotate element with @ContextualSerialization", "To use context serializer as fallback, explicitly annotate element with @ContextualSerialization",
null, null,
@@ -116,7 +128,6 @@ fun AbstractSerialGenerator.findTypeSerializerOrContext(
fun findTypeSerializer(module: ModuleDescriptor, kType: KotlinType): ClassDescriptor? { fun findTypeSerializer(module: ModuleDescriptor, kType: KotlinType): ClassDescriptor? {
val userOverride = kType.overridenSerializer val userOverride = kType.overridenSerializer
if (userOverride != null) return userOverride.toClassDescriptor if (userOverride != null) return userOverride.toClassDescriptor
if (kType.requiresPolymorphism()) return findPolymorphicSerializer(module)
if (kType.isTypeParameter()) return null if (kType.isTypeParameter()) return null
if (KotlinBuiltIns.isArray(kType)) return module.getClassFromInternalSerializationPackage(SpecialBuiltins.referenceArraySerializer) if (KotlinBuiltIns.isArray(kType)) return module.getClassFromInternalSerializationPackage(SpecialBuiltins.referenceArraySerializer)
return kType.typeSerializer.toClassDescriptor // check for serializer defined on the type 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 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<PropertyDescriptor, KtProperty> = declarations fun KtPureClassOrObject.bodyPropertiesDescriptorsMap(bindingContext: BindingContext): Map<PropertyDescriptor, KtProperty> = declarations
.asSequence() .asSequence()
.filterIsInstance<KtProperty>() .filterIsInstance<KtProperty>()
@@ -22,6 +22,7 @@ object SerializationAnnotations {
internal val serialInfoFqName = FqName("kotlinx.serialization.SerialInfo") internal val serialInfoFqName = FqName("kotlinx.serialization.SerialInfo")
internal val contextualFqName = FqName("kotlinx.serialization.ContextualSerialization") internal val contextualFqName = FqName("kotlinx.serialization.ContextualSerialization")
internal val polymorphicFqName = FqName("kotlinx.serialization.Polymorphic")
internal val additionalSerializersFqName = FqName("kotlinx.serialization.UseSerializers") internal val additionalSerializersFqName = FqName("kotlinx.serialization.UseSerializers")
} }
@@ -19,13 +19,12 @@ package org.jetbrains.kotlinx.serialization.compiler.resolve
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.psi.KtDeclarationWithInitializer import org.jetbrains.kotlin.psi.KtDeclarationWithInitializer
import org.jetbrains.kotlin.psi.KtParameter import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.psi.ValueArgument import org.jetbrains.kotlin.psi.ValueArgument
import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.source.getPsi import org.jetbrains.kotlin.resolve.source.getPsi
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlinx.serialization.compiler.backend.common.analyzeSpecialSerializers
class SerializableProperty( class SerializableProperty(
val descriptor: PropertyDescriptor, val descriptor: PropertyDescriptor,
@@ -36,18 +35,11 @@ class SerializableProperty(
val type = descriptor.type val type = descriptor.type
val genericIndex = type.genericIndex val genericIndex = type.genericIndex
val module = descriptor.module 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 optional = !descriptor.annotations.serialRequired && descriptor.declaresDefaultValue
val transient = descriptor.annotations.serialTransient || !hasBackingField val transient = descriptor.annotations.serialTransient || !hasBackingField
val annotationsWithArguments: List<Triple<ClassDescriptor, List<ValueArgument>, List<ValueParameterDescriptor>>> = val annotationsWithArguments: List<Triple<ClassDescriptor, List<ValueArgument>, List<ValueParameterDescriptor>>> =
descriptor.annotationsWithArguments() 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 val PropertyDescriptor.declaresDefaultValue: Boolean