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(
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<PropertyDescriptor, KtProperty> = declarations
.asSequence()
.filterIsInstance<KtProperty>()
@@ -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")
}
@@ -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<Triple<ClassDescriptor, List<ValueArgument>, List<ValueParameterDescriptor>>> =
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