[kx.serialization] Fix serializer resolving for file-level annotations:

Instantiating ContextSerializer for primitives with boxing (fixes https://github.com/Kotlin/kotlinx.serialization/issues/349)
Unwrap nullable type when looking for general-defined serializer (fixes https://github.com/Kotlin/kotlinx.serialization/issues/351)

Add lost java collection types and fix annotation name (fixes https://github.com/Kotlin/kotlinx.serialization/issues/343)
This commit is contained in:
Leonid Startsev
2019-01-28 17:19:17 +03:00
parent 738271aba6
commit 8eeb9d4faa
2 changed files with 30 additions and 11 deletions
@@ -32,10 +32,7 @@ import org.jetbrains.kotlin.psi.KtPureClassOrObject
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.containsTypeProjectionsInTopLevelArguments
import org.jetbrains.kotlin.types.typeUtil.isBoolean
import org.jetbrains.kotlin.types.typeUtil.isPrimitiveNumberType
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
import org.jetbrains.kotlin.types.typeUtil.*
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.enumSerializerId
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.polymorphicSerializerId
import org.jetbrains.kotlinx.serialization.compiler.backend.jvm.referenceArraySerializerId
@@ -49,8 +46,13 @@ open class SerialTypeInfo(
val unit: Boolean = false
)
fun AbstractSerialGenerator.findAddOnSerializer(propertyType: KotlinType): ClassDescriptor? =
additionalSerializersInScopeOfCurrentFile[propertyType]
fun AbstractSerialGenerator.findAddOnSerializer(propertyType: KotlinType, module: ModuleDescriptor): ClassDescriptor? {
additionalSerializersInScopeOfCurrentFile[propertyType]?.let { return it }
if (propertyType in contextualKClassListInCurrentFile)
return module.getClassFromSerializationPackage(SpecialBuiltins.contextSerializer)
if (propertyType.isMarkedNullable) return findAddOnSerializer(propertyType.makeNotNullable(), module)
return null
}
@Suppress("FunctionName", "LocalVariableName")
fun AbstractSerialGenerator.getSerialTypeInfo(property: SerializableProperty): SerialTypeInfo {
@@ -59,8 +61,8 @@ 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) }
findAddOnSerializer(T)?.let { return SerializableInfo(it) }
return when {
T.isTypeParameter() -> SerialTypeInfo(property, if (property.type.isMarkedNullable) "Nullable" else "", null)
T.isPrimitiveNumberType() or T.isBoolean() -> SerialTypeInfo(
@@ -95,8 +97,9 @@ fun AbstractSerialGenerator.findTypeSerializerOrContext(
annotations: Annotations = kType.annotations,
sourceElement: PsiElement? = null
): ClassDescriptor? {
additionalSerializersInScopeOfCurrentFile[kType]?.let { return it }
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)
@@ -104,7 +107,7 @@ fun AbstractSerialGenerator.findTypeSerializerOrContext(
null
return getContextualSerializer() ?: 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 @ContextualSerializer",
"To use context serializer as fallback, explicitly annotate element with @ContextualSerialization",
null,
sourceElement
)
@@ -142,6 +145,21 @@ fun findStandardKotlinTypeSerializer(module: ModuleDescriptor, kType: KotlinType
"kotlin.collections.Map", "kotlin.collections.LinkedHashMap", "kotlin.collections.MutableMap" -> "LinkedHashMapSerializer"
"kotlin.collections.HashMap" -> "HashMapSerializer"
"kotlin.collections.Map.Entry" -> "MapEntrySerializer"
"java.lang.Boolean" -> "BooleanSerializer"
"java.lang.Byte" -> "ByteSerializer"
"java.lang.Short" -> "ShortSerializer"
"java.lang.Integer" -> "IntSerializer"
"java.lang.Long" -> "LongSerializer"
"java.lang.Float" -> "FloatSerializer"
"java.lang.Double" -> "DoubleSerializer"
"java.lang.Character" -> "CharSerializer"
"java.lang.String" -> "StringSerializer"
"java.util.Collection", "java.util.List", "java.util.ArrayList" -> "ArrayListSerializer"
"java.util.Set", "java.util.LinkedHashSet" -> "LinkedHashSetSerializer"
"java.util.HashSet" -> "HashSetSerializer"
"java.util.Map", "java.util.LinkedHashMap" -> "LinkedHashMapSerializer"
"java.util.HashMap" -> "HashMapSerializer"
"java.util.Map.Entry" -> "MapEntrySerializer"
else -> return null
}
return module.findClassAcrossModuleDependencies(ClassId(internalPackageFqName, Name.identifier(name)))
@@ -256,7 +256,8 @@ internal fun AbstractSerialGenerator.stackValueSerializerInstance(codegen: Class
when (serializer.classId) {
enumSerializerId, contextSerializerId -> {
// a special way to instantiate enum -- need a enum KClass reference
aconst(codegen.typeMapper.mapType(kType))
// GENERIC_ARGUMENT forces boxing in order to obtain KClass
aconst(codegen.typeMapper.mapType(kType, null, TypeMappingMode.GENERIC_ARGUMENT))
AsmUtil.wrapJavaClassIntoKClass(this)
signature.append(AsmTypes.K_CLASS_TYPE.descriptor)
}
@@ -320,8 +321,8 @@ 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) }
findAddOnSerializer(property.type)?.let { return SerializableInfo(it) }
if (property.type.isTypeParameter()) return JVMSerialTypeInfo(
property,